blob: f72e3b3dca6953542d0f659d0f2b512ba4cf4f24 [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 Frenchd4dc2772021-07-07 14:03:54 -05002540 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Steve French50c2f752007-07-13 00:33:32 +00002541 parm_data = (struct cifs_posix_lock *)
Steve Frenchd4dc2772021-07-07 14:03:54 -05002542 (((char *)pSMB) + offset + 4);
Steve French08547b02006-02-28 22:39:25 +00002543
2544 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002545 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002546 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002547 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002548 pSMB->Timeout = cpu_to_le32(-1);
2549 } else
2550 pSMB->Timeout = 0;
2551
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002552 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002553 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002554 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002555
2556 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002557 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002558 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2559 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002560 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002561 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002562 if (waitFlag) {
2563 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2564 (struct smb_hdr *) pSMBr, &bytes_returned);
2565 } else {
Steve French133672e2007-11-13 22:41:37 +00002566 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002567 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002568 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002569 &resp_buf_type, timeout, &rsp_iov);
2570 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002571 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002572 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002573
Steve French08547b02006-02-28 22:39:25 +00002574 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002575 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002576 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002577 /* lock structure can be returned on get */
2578 __u16 data_offset;
2579 __u16 data_count;
2580 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002581
Jeff Layton820a8032011-05-04 08:05:26 -04002582 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002583 rc = -EIO; /* bad smb */
2584 goto plk_err_exit;
2585 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002586 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2587 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002588 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002589 rc = -EIO;
2590 goto plk_err_exit;
2591 }
2592 parm_data = (struct cifs_posix_lock *)
2593 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002594 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002595 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002596 else {
2597 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002598 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002599 pLockData->fl_type = F_RDLCK;
2600 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002601 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002602 pLockData->fl_type = F_WRLCK;
2603
Steve French5443d132011-03-13 05:08:25 +00002604 pLockData->fl_start = le64_to_cpu(parm_data->start);
2605 pLockData->fl_end = pLockData->fl_start +
2606 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002607 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002608 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002609 }
Steve French50c2f752007-07-13 00:33:32 +00002610
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002611plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002612 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002613
Steve French08547b02006-02-28 22:39:25 +00002614 /* Note: On -EAGAIN error only caller can retry on handle based calls
2615 since file handle passed in no longer valid */
2616
2617 return rc;
2618}
2619
2620
2621int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002622CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
2624 int rc = 0;
2625 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002626 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628/* do not retry on dead session on close */
2629 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002630 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return 0;
2632 if (rc)
2633 return rc;
2634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002636 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002638 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002639 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002640 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002642 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002644 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
2646 }
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002649 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 rc = 0;
2651
2652 return rc;
2653}
2654
2655int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002656CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002657{
2658 int rc = 0;
2659 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002660 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002661
2662 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2663 if (rc)
2664 return rc;
2665
2666 pSMB->FileID = (__u16) smb_file_id;
2667 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002668 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002669 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002670 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002671 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002672 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002673
2674 return rc;
2675}
2676
2677int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002678CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002679 const char *from_name, const char *to_name,
2680 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
2682 int rc = 0;
2683 RENAME_REQ *pSMB = NULL;
2684 RENAME_RSP *pSMBr = NULL;
2685 int bytes_returned;
2686 int name_len, name_len2;
2687 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002688 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Joe Perchesf96637b2013-05-04 22:12:25 -05002690 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691renameRetry:
2692 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2693 (void **) &pSMBr);
2694 if (rc)
2695 return rc;
2696
2697 pSMB->BufferFormat = 0x04;
2698 pSMB->SearchAttributes =
2699 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2700 ATTR_DIRECTORY);
2701
2702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002703 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2704 from_name, PATH_MAX,
2705 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 name_len++; /* trailing null */
2707 name_len *= 2;
2708 pSMB->OldFileName[name_len] = 0x04; /* pad */
2709 /* protocol requires ASCII signature byte on Unicode string */
2710 pSMB->OldFileName[name_len + 1] = 0x00;
2711 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002712 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002713 to_name, PATH_MAX, cifs_sb->local_nls,
2714 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2716 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002717 } else {
2718 name_len = copy_path_name(pSMB->OldFileName, from_name);
2719 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 name_len2++; /* signature byte */
2722 }
2723
2724 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002725 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 pSMB->ByteCount = cpu_to_le16(count);
2727
2728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002730 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002731 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002732 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 cifs_buf_release(pSMB);
2735
2736 if (rc == -EAGAIN)
2737 goto renameRetry;
2738
2739 return rc;
2740}
2741
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002742int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002743 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002744 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
2746 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2747 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002748 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 char *data_offset;
2750 char dummy_string[30];
2751 int rc = 0;
2752 int bytes_returned = 0;
2753 int len_of_str;
2754 __u16 params, param_offset, offset, count, byte_count;
2755
Joe Perchesf96637b2013-05-04 22:12:25 -05002756 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2758 (void **) &pSMBr);
2759 if (rc)
2760 return rc;
2761
2762 params = 6;
2763 pSMB->MaxSetupCount = 0;
2764 pSMB->Reserved = 0;
2765 pSMB->Flags = 0;
2766 pSMB->Timeout = 0;
2767 pSMB->Reserved2 = 0;
2768 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2769 offset = param_offset + params;
2770
Steve Frenchf3717932021-07-07 13:34:47 -05002771 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2772 data_offset = (char *)(pSMB) + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 rename_info = (struct set_file_rename *) data_offset;
2774 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002775 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 pSMB->SetupCount = 1;
2777 pSMB->Reserved3 = 0;
2778 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2779 byte_count = 3 /* pad */ + params;
2780 pSMB->ParameterCount = cpu_to_le16(params);
2781 pSMB->TotalParameterCount = pSMB->ParameterCount;
2782 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2783 pSMB->DataOffset = cpu_to_le16(offset);
2784 /* construct random name ".cifs_tmp<inodenum><mid>" */
2785 rename_info->overwrite = cpu_to_le32(1);
2786 rename_info->root_fid = 0;
2787 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002788 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002789 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002790 len_of_str =
2791 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002792 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002794 len_of_str =
2795 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002796 target_name, PATH_MAX, nls_codepage,
2797 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 }
2799 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002800 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 byte_count += count;
2802 pSMB->DataCount = cpu_to_le16(count);
2803 pSMB->TotalDataCount = pSMB->DataCount;
2804 pSMB->Fid = netfid;
2805 pSMB->InformationLevel =
2806 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2807 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002808 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 pSMB->ByteCount = cpu_to_le16(byte_count);
2810 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002812 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002813 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002814 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2815 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 cifs_buf_release(pSMB);
2818
2819 /* Note: On -EAGAIN error only caller can retry on handle based calls
2820 since file handle passed in no longer valid */
2821
2822 return rc;
2823}
2824
2825int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002826CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2827 const char *fromName, const __u16 target_tid, const char *toName,
2828 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829{
2830 int rc = 0;
2831 COPY_REQ *pSMB = NULL;
2832 COPY_RSP *pSMBr = NULL;
2833 int bytes_returned;
2834 int name_len, name_len2;
2835 __u16 count;
2836
Joe Perchesf96637b2013-05-04 22:12:25 -05002837 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838copyRetry:
2839 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2840 (void **) &pSMBr);
2841 if (rc)
2842 return rc;
2843
2844 pSMB->BufferFormat = 0x04;
2845 pSMB->Tid2 = target_tid;
2846
2847 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2848
2849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002850 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2851 fromName, PATH_MAX, nls_codepage,
2852 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len++; /* trailing null */
2854 name_len *= 2;
2855 pSMB->OldFileName[name_len] = 0x04; /* pad */
2856 /* protocol requires ASCII signature byte on Unicode string */
2857 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002858 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002859 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2860 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2862 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002863 } else {
2864 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002866 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 name_len2++; /* signature byte */
2868 }
2869
2870 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002871 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 pSMB->ByteCount = cpu_to_le16(count);
2873
2874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2876 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002877 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2878 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
Steve French0d817bc2008-05-22 02:02:03 +00002880 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881
2882 if (rc == -EAGAIN)
2883 goto copyRetry;
2884
2885 return rc;
2886}
2887
2888int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002889CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002891 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892{
2893 TRANSACTION2_SPI_REQ *pSMB = NULL;
2894 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2895 char *data_offset;
2896 int name_len;
2897 int name_len_target;
2898 int rc = 0;
2899 int bytes_returned = 0;
2900 __u16 params, param_offset, offset, byte_count;
2901
Joe Perchesf96637b2013-05-04 22:12:25 -05002902 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903createSymLinkRetry:
2904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2905 (void **) &pSMBr);
2906 if (rc)
2907 return rc;
2908
2909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2910 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002911 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2912 /* find define for this maxpathcomponent */
2913 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 name_len++; /* trailing null */
2915 name_len *= 2;
2916
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002917 } else {
2918 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 }
2920 params = 6 + name_len;
2921 pSMB->MaxSetupCount = 0;
2922 pSMB->Reserved = 0;
2923 pSMB->Flags = 0;
2924 pSMB->Timeout = 0;
2925 pSMB->Reserved2 = 0;
2926 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002927 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 offset = param_offset + params;
2929
Steve Frenchded2d992021-07-01 20:44:27 -05002930 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2931 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2933 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002934 cifsConvertToUTF16((__le16 *) data_offset, toName,
2935 /* find define for this maxpathcomponent */
2936 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 name_len_target++; /* trailing null */
2938 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002939 } else {
2940 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 }
2942
2943 pSMB->MaxParameterCount = cpu_to_le16(2);
2944 /* BB find exact max on data count below from sess */
2945 pSMB->MaxDataCount = cpu_to_le16(1000);
2946 pSMB->SetupCount = 1;
2947 pSMB->Reserved3 = 0;
2948 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2949 byte_count = 3 /* pad */ + params + name_len_target;
2950 pSMB->DataCount = cpu_to_le16(name_len_target);
2951 pSMB->ParameterCount = cpu_to_le16(params);
2952 pSMB->TotalDataCount = pSMB->DataCount;
2953 pSMB->TotalParameterCount = pSMB->ParameterCount;
2954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2955 pSMB->DataOffset = cpu_to_le16(offset);
2956 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2957 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002958 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 pSMB->ByteCount = cpu_to_le16(byte_count);
2960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002962 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002963 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002964 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2965 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Steve French0d817bc2008-05-22 02:02:03 +00002967 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
2969 if (rc == -EAGAIN)
2970 goto createSymLinkRetry;
2971
2972 return rc;
2973}
2974
2975int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002976CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979{
2980 TRANSACTION2_SPI_REQ *pSMB = NULL;
2981 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2982 char *data_offset;
2983 int name_len;
2984 int name_len_target;
2985 int rc = 0;
2986 int bytes_returned = 0;
2987 __u16 params, param_offset, offset, byte_count;
2988
Joe Perchesf96637b2013-05-04 22:12:25 -05002989 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990createHardLinkRetry:
2991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2992 (void **) &pSMBr);
2993 if (rc)
2994 return rc;
2995
2996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002997 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2998 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 name_len++; /* trailing null */
3000 name_len *= 2;
3001
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003002 } else {
3003 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 }
3005 params = 6 + name_len;
3006 pSMB->MaxSetupCount = 0;
3007 pSMB->Reserved = 0;
3008 pSMB->Flags = 0;
3009 pSMB->Timeout = 0;
3010 pSMB->Reserved2 = 0;
3011 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003012 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 offset = param_offset + params;
3014
Steve French819f9162021-07-01 17:46:23 -05003015 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
3016 data_offset = (char *)pSMB + offset + 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3018 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003019 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3020 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 name_len_target++; /* trailing null */
3022 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003023 } else {
3024 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 }
3026
3027 pSMB->MaxParameterCount = cpu_to_le16(2);
3028 /* BB find exact max on data count below from sess*/
3029 pSMB->MaxDataCount = cpu_to_le16(1000);
3030 pSMB->SetupCount = 1;
3031 pSMB->Reserved3 = 0;
3032 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3033 byte_count = 3 /* pad */ + params + name_len_target;
3034 pSMB->ParameterCount = cpu_to_le16(params);
3035 pSMB->TotalParameterCount = pSMB->ParameterCount;
3036 pSMB->DataCount = cpu_to_le16(name_len_target);
3037 pSMB->TotalDataCount = pSMB->DataCount;
3038 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3039 pSMB->DataOffset = cpu_to_le16(offset);
3040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3041 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003042 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 pSMB->ByteCount = cpu_to_le16(byte_count);
3044 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3045 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003046 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003047 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003048 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3049 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
3051 cifs_buf_release(pSMB);
3052 if (rc == -EAGAIN)
3053 goto createHardLinkRetry;
3054
3055 return rc;
3056}
3057
3058int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003059CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003060 const char *from_name, const char *to_name,
3061 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062{
3063 int rc = 0;
3064 NT_RENAME_REQ *pSMB = NULL;
3065 RENAME_RSP *pSMBr = NULL;
3066 int bytes_returned;
3067 int name_len, name_len2;
3068 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003069 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
Joe Perchesf96637b2013-05-04 22:12:25 -05003071 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072winCreateHardLinkRetry:
3073
3074 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3075 (void **) &pSMBr);
3076 if (rc)
3077 return rc;
3078
3079 pSMB->SearchAttributes =
3080 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3081 ATTR_DIRECTORY);
3082 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3083 pSMB->ClusterCount = 0;
3084
3085 pSMB->BufferFormat = 0x04;
3086
3087 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3088 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003089 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3090 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 name_len++; /* trailing null */
3092 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003093
3094 /* protocol specifies ASCII buffer format (0x04) for unicode */
3095 pSMB->OldFileName[name_len] = 0x04;
3096 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003098 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003099 to_name, PATH_MAX, cifs_sb->local_nls,
3100 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3102 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003103 } else {
3104 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003106 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 name_len2++; /* signature byte */
3108 }
3109
3110 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003111 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 pSMB->ByteCount = cpu_to_le16(count);
3113
3114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003116 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003117 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003118 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 cifs_buf_release(pSMB);
3121 if (rc == -EAGAIN)
3122 goto winCreateHardLinkRetry;
3123
3124 return rc;
3125}
3126
3127int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003128CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003129 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003130 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131{
3132/* SMB_QUERY_FILE_UNIX_LINK */
3133 TRANSACTION2_QPI_REQ *pSMB = NULL;
3134 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3135 int rc = 0;
3136 int bytes_returned;
3137 int name_len;
3138 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003139 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
Joe Perchesf96637b2013-05-04 22:12:25 -05003141 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
3143querySymLinkRetry:
3144 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3145 (void **) &pSMBr);
3146 if (rc)
3147 return rc;
3148
3149 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3150 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003151 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3152 searchName, PATH_MAX, nls_codepage,
3153 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 name_len++; /* trailing null */
3155 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003156 } else {
3157 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 }
3159
3160 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3161 pSMB->TotalDataCount = 0;
3162 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003163 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 pSMB->MaxSetupCount = 0;
3165 pSMB->Reserved = 0;
3166 pSMB->Flags = 0;
3167 pSMB->Timeout = 0;
3168 pSMB->Reserved2 = 0;
3169 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003170 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 pSMB->DataCount = 0;
3172 pSMB->DataOffset = 0;
3173 pSMB->SetupCount = 1;
3174 pSMB->Reserved3 = 0;
3175 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3176 byte_count = params + 1 /* pad */ ;
3177 pSMB->TotalParameterCount = cpu_to_le16(params);
3178 pSMB->ParameterCount = pSMB->TotalParameterCount;
3179 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3180 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003181 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 pSMB->ByteCount = cpu_to_le16(byte_count);
3183
3184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3186 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003187 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 } else {
3189 /* decode response */
3190
3191 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003193 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003194 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003196 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003197 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
Jeff Layton460b9692009-04-30 07:17:56 -04003199 data_start = ((char *) &pSMBr->hdr.Protocol) +
3200 le16_to_cpu(pSMBr->t2.DataOffset);
3201
Steve French0e0d2cf2009-05-01 05:27:32 +00003202 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3203 is_unicode = true;
3204 else
3205 is_unicode = false;
3206
Steve French737b7582005-04-28 22:41:06 -07003207 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003208 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3209 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003210 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003211 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 }
3213 }
3214 cifs_buf_release(pSMB);
3215 if (rc == -EAGAIN)
3216 goto querySymLinkRetry;
3217 return rc;
3218}
3219
Steve Frenchc52a95542011-02-24 06:16:22 +00003220/*
3221 * Recent Windows versions now create symlinks more frequently
3222 * and they use the "reparse point" mechanism below. We can of course
3223 * do symlinks nicely to Samba and other servers which support the
3224 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3225 * "MF" symlinks optionally, but for recent Windows we really need to
3226 * reenable the code below and fix the cifs_symlink callers to handle this.
3227 * In the interim this code has been moved to its own config option so
3228 * it is not compiled in by default until callers fixed up and more tested.
3229 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003231CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3232 __u16 fid, char **symlinkinfo,
3233 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234{
3235 int rc = 0;
3236 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003237 struct smb_com_transaction_ioctl_req *pSMB;
3238 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003239 bool is_unicode;
3240 unsigned int sub_len;
3241 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003242 struct reparse_symlink_data *reparse_buf;
3243 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003244 __u32 data_offset, data_count;
3245 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003247 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3249 (void **) &pSMBr);
3250 if (rc)
3251 return rc;
3252
3253 pSMB->TotalParameterCount = 0 ;
3254 pSMB->TotalDataCount = 0;
3255 pSMB->MaxParameterCount = cpu_to_le32(2);
3256 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003257 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 pSMB->MaxSetupCount = 4;
3259 pSMB->Reserved = 0;
3260 pSMB->ParameterOffset = 0;
3261 pSMB->DataCount = 0;
3262 pSMB->DataOffset = 0;
3263 pSMB->SetupCount = 4;
3264 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
3266 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3267 pSMB->IsFsctl = 1; /* FSCTL */
3268 pSMB->IsRootFlag = 0;
3269 pSMB->Fid = fid; /* file handle always le */
3270 pSMB->ByteCount = 0;
3271
3272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3273 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3274 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003275 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003276 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 }
Steve French989c7e52009-05-02 05:32:20 +00003278
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003279 data_offset = le32_to_cpu(pSMBr->DataOffset);
3280 data_count = le32_to_cpu(pSMBr->DataCount);
3281 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3282 /* BB also check enough total bytes returned */
3283 rc = -EIO; /* bad smb */
3284 goto qreparse_out;
3285 }
3286 if (!data_count || (data_count > 2048)) {
3287 rc = -EIO;
3288 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3289 goto qreparse_out;
3290 }
3291 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003292 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003293 ((char *)&pSMBr->hdr.Protocol + data_offset);
3294 if ((char *)reparse_buf >= end_of_smb) {
3295 rc = -EIO;
3296 goto qreparse_out;
3297 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003298 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3299 cifs_dbg(FYI, "NFS style reparse tag\n");
3300 posix_buf = (struct reparse_posix_data *)reparse_buf;
3301
3302 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3303 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3304 le64_to_cpu(posix_buf->InodeType));
3305 rc = -EOPNOTSUPP;
3306 goto qreparse_out;
3307 }
3308 is_unicode = true;
3309 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3310 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3311 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3312 rc = -EIO;
3313 goto qreparse_out;
3314 }
3315 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3316 sub_len, is_unicode, nls_codepage);
3317 goto qreparse_out;
3318 } else if (reparse_buf->ReparseTag !=
3319 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3320 rc = -EOPNOTSUPP;
3321 goto qreparse_out;
3322 }
3323
3324 /* Reparse tag is NTFS symlink */
3325 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3326 reparse_buf->PathBuffer;
3327 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3328 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003329 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3330 rc = -EIO;
3331 goto qreparse_out;
3332 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003333 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3334 is_unicode = true;
3335 else
3336 is_unicode = false;
3337
3338 /* BB FIXME investigate remapping reserved chars here */
3339 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3340 nls_codepage);
3341 if (!*symlinkinfo)
3342 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003344 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003346 /*
3347 * Note: On -EAGAIN error only caller can retry on handle based calls
3348 * since file handle passed in no longer valid.
3349 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 return rc;
3351}
3352
Steve Frenchc7f508a2013-10-14 15:27:32 -05003353int
3354CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3355 __u16 fid)
3356{
3357 int rc = 0;
3358 int bytes_returned;
3359 struct smb_com_transaction_compr_ioctl_req *pSMB;
3360 struct smb_com_transaction_ioctl_rsp *pSMBr;
3361
3362 cifs_dbg(FYI, "Set compression for %u\n", fid);
3363 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3364 (void **) &pSMBr);
3365 if (rc)
3366 return rc;
3367
3368 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3369
3370 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003371 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003372 pSMB->MaxParameterCount = 0;
3373 pSMB->MaxDataCount = 0;
3374 pSMB->MaxSetupCount = 4;
3375 pSMB->Reserved = 0;
3376 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003377 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003378 pSMB->DataOffset =
3379 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3380 compression_state) - 4); /* 84 */
3381 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003382 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003383 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003384 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003385 pSMB->IsFsctl = 1; /* FSCTL */
3386 pSMB->IsRootFlag = 0;
3387 pSMB->Fid = fid; /* file handle always le */
3388 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003389 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003390 inc_rfc1001_len(pSMB, 5);
3391
3392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3394 if (rc)
3395 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3396
3397 cifs_buf_release(pSMB);
3398
3399 /*
3400 * Note: On -EAGAIN error only caller can retry on handle based calls
3401 * since file handle passed in no longer valid.
3402 */
3403 return rc;
3404}
3405
3406
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407#ifdef CONFIG_CIFS_POSIX
3408
3409/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003410static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003411 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
3413 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003414 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3415 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3416 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003417/*
3418 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3419 ace->e_perm, ace->e_tag, ace->e_id);
3420*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 return;
3423}
3424
3425/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003426static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3427 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429 int size = 0;
3430 int i;
3431 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003432 struct cifs_posix_ace *pACE;
3433 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003434 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
3436 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3437 return -EOPNOTSUPP;
3438
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003439 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 count = le16_to_cpu(cifs_acl->access_entry_count);
3441 pACE = &cifs_acl->ace_array[0];
3442 size = sizeof(struct cifs_posix_acl);
3443 size += sizeof(struct cifs_posix_ace) * count;
3444 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003445 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003446 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3447 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 return -EINVAL;
3449 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003450 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 count = le16_to_cpu(cifs_acl->access_entry_count);
3452 size = sizeof(struct cifs_posix_acl);
3453 size += sizeof(struct cifs_posix_ace) * count;
3454/* skip past access ACEs to get to default ACEs */
3455 pACE = &cifs_acl->ace_array[count];
3456 count = le16_to_cpu(cifs_acl->default_entry_count);
3457 size += sizeof(struct cifs_posix_ace) * count;
3458 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003459 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 return -EINVAL;
3461 } else {
3462 /* illegal type */
3463 return -EINVAL;
3464 }
3465
3466 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003467 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003468 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003469 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 return -ERANGE;
3471 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003472 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3473
Steve Frenchff7feac2005-11-15 16:45:16 -08003474 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003475 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003476 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003477 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 }
3479 }
3480 return size;
3481}
3482
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303483static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003484 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485{
Steve Frenchff7feac2005-11-15 16:45:16 -08003486 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3487 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003489 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 /* Probably no need to le convert -1 on any arch but can not hurt */
3491 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003492 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003493 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003494/*
3495 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3496 ace->e_perm, ace->e_tag, ace->e_id);
3497*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498}
3499
3500/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003501static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3502 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503{
3504 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003505 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003506 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003507 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 int count;
3509 int i;
3510
Steve French790fe572007-07-07 19:25:05 +00003511 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 return 0;
3513
3514 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003515 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3516 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003517 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003518 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3519 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 return 0;
3521 }
3522 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003523 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003524 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003525 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003526 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003527 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003528 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003529 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003530 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 return 0;
3532 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303533 for (i = 0; i < count; i++)
3534 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003535 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3537 rc += sizeof(struct cifs_posix_acl);
3538 /* BB add check to make sure ACL does not overflow SMB */
3539 }
3540 return rc;
3541}
3542
3543int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003544CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003545 const unsigned char *searchName,
3546 char *acl_inf, const int buflen, const int acl_type,
3547 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548{
3549/* SMB_QUERY_POSIX_ACL */
3550 TRANSACTION2_QPI_REQ *pSMB = NULL;
3551 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3552 int rc = 0;
3553 int bytes_returned;
3554 int name_len;
3555 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003556
Joe Perchesf96637b2013-05-04 22:12:25 -05003557 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559queryAclRetry:
3560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3561 (void **) &pSMBr);
3562 if (rc)
3563 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003564
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3566 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003567 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3568 searchName, PATH_MAX, nls_codepage,
3569 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 name_len++; /* trailing null */
3571 name_len *= 2;
3572 pSMB->FileName[name_len] = 0;
3573 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003574 } else {
3575 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 }
3577
3578 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3579 pSMB->TotalDataCount = 0;
3580 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003581 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 pSMB->MaxDataCount = cpu_to_le16(4000);
3583 pSMB->MaxSetupCount = 0;
3584 pSMB->Reserved = 0;
3585 pSMB->Flags = 0;
3586 pSMB->Timeout = 0;
3587 pSMB->Reserved2 = 0;
3588 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003589 offsetof(struct smb_com_transaction2_qpi_req,
3590 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 pSMB->DataCount = 0;
3592 pSMB->DataOffset = 0;
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3596 byte_count = params + 1 /* pad */ ;
3597 pSMB->TotalParameterCount = cpu_to_le16(params);
3598 pSMB->ParameterCount = pSMB->TotalParameterCount;
3599 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3600 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003601 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 pSMB->ByteCount = cpu_to_le16(byte_count);
3603
3604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003606 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003608 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 } else {
3610 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003611
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003614 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 rc = -EIO; /* bad smb */
3616 else {
3617 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3618 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3619 rc = cifs_copy_posix_acl(acl_inf,
3620 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003621 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 }
3623 }
3624 cifs_buf_release(pSMB);
3625 if (rc == -EAGAIN)
3626 goto queryAclRetry;
3627 return rc;
3628}
3629
3630int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003631CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003632 const unsigned char *fileName,
3633 const char *local_acl, const int buflen,
3634 const int acl_type,
3635 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636{
3637 struct smb_com_transaction2_spi_req *pSMB = NULL;
3638 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3639 char *parm_data;
3640 int name_len;
3641 int rc = 0;
3642 int bytes_returned = 0;
3643 __u16 params, byte_count, data_count, param_offset, offset;
3644
Joe Perchesf96637b2013-05-04 22:12:25 -05003645 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646setAclRetry:
3647 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003648 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 if (rc)
3650 return rc;
3651 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3652 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003653 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3654 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 name_len++; /* trailing null */
3656 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003657 } else {
3658 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 }
3660 params = 6 + name_len;
3661 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003662 /* BB find max SMB size from sess */
3663 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 pSMB->MaxSetupCount = 0;
3665 pSMB->Reserved = 0;
3666 pSMB->Flags = 0;
3667 pSMB->Timeout = 0;
3668 pSMB->Reserved2 = 0;
3669 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003670 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 offset = param_offset + params;
3672 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3673 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3674
3675 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003676 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
Steve French790fe572007-07-07 19:25:05 +00003678 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 rc = -EOPNOTSUPP;
3680 goto setACLerrorExit;
3681 }
3682 pSMB->DataOffset = cpu_to_le16(offset);
3683 pSMB->SetupCount = 1;
3684 pSMB->Reserved3 = 0;
3685 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3687 byte_count = 3 /* pad */ + params + data_count;
3688 pSMB->DataCount = cpu_to_le16(data_count);
3689 pSMB->TotalDataCount = pSMB->DataCount;
3690 pSMB->ParameterCount = cpu_to_le16(params);
3691 pSMB->TotalParameterCount = pSMB->ParameterCount;
3692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003693 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 pSMB->ByteCount = cpu_to_le16(byte_count);
3695 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003697 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003698 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
3700setACLerrorExit:
3701 cifs_buf_release(pSMB);
3702 if (rc == -EAGAIN)
3703 goto setAclRetry;
3704 return rc;
3705}
3706
Steve Frenchf654bac2005-04-28 22:41:04 -07003707/* BB fix tabs in this function FIXME BB */
3708int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003709CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003710 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003711{
Steve French50c2f752007-07-13 00:33:32 +00003712 int rc = 0;
3713 struct smb_t2_qfi_req *pSMB = NULL;
3714 struct smb_t2_qfi_rsp *pSMBr = NULL;
3715 int bytes_returned;
3716 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003717
Joe Perchesf96637b2013-05-04 22:12:25 -05003718 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003719 if (tcon == NULL)
3720 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003721
3722GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003723 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3724 (void **) &pSMBr);
3725 if (rc)
3726 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003727
Steve Frenchad7a2922008-02-07 23:25:02 +00003728 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003729 pSMB->t2.TotalDataCount = 0;
3730 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3731 /* BB find exact max data count below from sess structure BB */
3732 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3733 pSMB->t2.MaxSetupCount = 0;
3734 pSMB->t2.Reserved = 0;
3735 pSMB->t2.Flags = 0;
3736 pSMB->t2.Timeout = 0;
3737 pSMB->t2.Reserved2 = 0;
3738 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3739 Fid) - 4);
3740 pSMB->t2.DataCount = 0;
3741 pSMB->t2.DataOffset = 0;
3742 pSMB->t2.SetupCount = 1;
3743 pSMB->t2.Reserved3 = 0;
3744 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3745 byte_count = params + 1 /* pad */ ;
3746 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3747 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3748 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3749 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003750 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003751 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003752 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003753
Steve French790fe572007-07-07 19:25:05 +00003754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3756 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003757 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003758 } else {
3759 /* decode response */
3760 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003761 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003762 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003763 /* If rc should we check for EOPNOSUPP and
3764 disable the srvino flag? or in caller? */
3765 rc = -EIO; /* bad smb */
3766 else {
3767 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3768 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3769 struct file_chattr_info *pfinfo;
3770 /* BB Do we need a cast or hash here ? */
3771 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003772 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003773 rc = -EIO;
3774 goto GetExtAttrOut;
3775 }
3776 pfinfo = (struct file_chattr_info *)
3777 (data_offset + (char *) &pSMBr->hdr.Protocol);
3778 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003779 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003780 }
3781 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003782GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003783 cifs_buf_release(pSMB);
3784 if (rc == -EAGAIN)
3785 goto GetExtAttrRetry;
3786 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003787}
3788
Steve Frenchf654bac2005-04-28 22:41:04 -07003789#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Jeff Layton79df1ba2010-12-06 12:52:08 -05003791/*
3792 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3793 * all NT TRANSACTS that we init here have total parm and data under about 400
3794 * bytes (to fit in small cifs buffer size), which is the case so far, it
3795 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3796 * returned setup area) and MaxParameterCount (returned parms size) must be set
3797 * by caller
3798 */
3799static int
3800smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003801 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003802 void **ret_buf)
3803{
3804 int rc;
3805 __u32 temp_offset;
3806 struct smb_com_ntransact_req *pSMB;
3807
3808 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3809 (void **)&pSMB);
3810 if (rc)
3811 return rc;
3812 *ret_buf = (void *)pSMB;
3813 pSMB->Reserved = 0;
3814 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3815 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003816 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003817 pSMB->ParameterCount = pSMB->TotalParameterCount;
3818 pSMB->DataCount = pSMB->TotalDataCount;
3819 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3820 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3821 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3822 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3823 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3824 pSMB->SubCommand = cpu_to_le16(sub_command);
3825 return 0;
3826}
3827
3828static int
3829validate_ntransact(char *buf, char **ppparm, char **ppdata,
3830 __u32 *pparmlen, __u32 *pdatalen)
3831{
3832 char *end_of_smb;
3833 __u32 data_count, data_offset, parm_count, parm_offset;
3834 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003835 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003836
3837 *pdatalen = 0;
3838 *pparmlen = 0;
3839
3840 if (buf == NULL)
3841 return -EINVAL;
3842
3843 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3844
Jeff Layton820a8032011-05-04 08:05:26 -04003845 bcc = get_bcc(&pSMBr->hdr);
3846 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003847 (char *)&pSMBr->ByteCount;
3848
3849 data_offset = le32_to_cpu(pSMBr->DataOffset);
3850 data_count = le32_to_cpu(pSMBr->DataCount);
3851 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3852 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3853
3854 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3855 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3856
3857 /* should we also check that parm and data areas do not overlap? */
3858 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003859 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003860 return -EINVAL;
3861 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003862 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003863 return -EINVAL;
3864 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003865 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003866 return -EINVAL;
3867 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003868 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3869 *ppdata, data_count, (data_count + *ppdata),
3870 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003871 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003872 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003873 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003874 return -EINVAL;
3875 }
3876 *pdatalen = data_count;
3877 *pparmlen = parm_count;
3878 return 0;
3879}
3880
Steve French0a4b92c2006-01-12 15:44:21 -08003881/* Get Security Descriptor (by handle) from remote server for a file or dir */
3882int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003883CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003884 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003885{
3886 int rc = 0;
3887 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003888 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003889 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003890 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003891
Joe Perchesf96637b2013-05-04 22:12:25 -05003892 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003893
Steve French630f3f0c2007-10-25 21:17:17 +00003894 *pbuflen = 0;
3895 *acl_inf = NULL;
3896
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003897 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003898 8 /* parm len */, tcon, (void **) &pSMB);
3899 if (rc)
3900 return rc;
3901
3902 pSMB->MaxParameterCount = cpu_to_le32(4);
3903 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3904 pSMB->MaxSetupCount = 0;
3905 pSMB->Fid = fid; /* file handle always le */
3906 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3907 CIFS_ACL_DACL);
3908 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003909 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003910 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003911 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003912
Steve Frencha761ac52007-10-18 21:45:27 +00003913 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003914 0, &rsp_iov);
3915 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003916 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003917 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003918 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003919 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003920 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003921 __u32 parm_len;
3922 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003923 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003924 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003925
3926/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003927 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003928 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003929 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003930 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003931 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003932
Joe Perchesf96637b2013-05-04 22:12:25 -05003933 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3934 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003935
3936 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3937 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003938 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003939 goto qsec_out;
3940 }
3941
3942/* BB check that data area is minimum length and as big as acl_len */
3943
Steve Frenchaf6f4612007-10-16 18:40:37 +00003944 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003945 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003946 cifs_dbg(VFS, "acl length %d does not match %d\n",
3947 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003948 if (*pbuflen > acl_len)
3949 *pbuflen = acl_len;
3950 }
Steve French0a4b92c2006-01-12 15:44:21 -08003951
Steve French630f3f0c2007-10-25 21:17:17 +00003952 /* check if buffer is big enough for the acl
3953 header followed by the smallest SID */
3954 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3955 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003956 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003957 rc = -EINVAL;
3958 *pbuflen = 0;
3959 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003960 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003961 if (*acl_inf == NULL) {
3962 *pbuflen = 0;
3963 rc = -ENOMEM;
3964 }
Steve French630f3f0c2007-10-25 21:17:17 +00003965 }
Steve French0a4b92c2006-01-12 15:44:21 -08003966 }
3967qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003968 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003969 return rc;
3970}
Steve French97837582007-12-31 07:47:21 +00003971
3972int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003973CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003974 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003975{
3976 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3977 int rc = 0;
3978 int bytes_returned = 0;
3979 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003980 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003981
3982setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003983 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003984 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003985 return rc;
Steve French97837582007-12-31 07:47:21 +00003986
3987 pSMB->MaxSetupCount = 0;
3988 pSMB->Reserved = 0;
3989
3990 param_count = 8;
3991 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3992 data_count = acllen;
3993 data_offset = param_offset + param_count;
3994 byte_count = 3 /* pad */ + param_count;
3995
3996 pSMB->DataCount = cpu_to_le32(data_count);
3997 pSMB->TotalDataCount = pSMB->DataCount;
3998 pSMB->MaxParameterCount = cpu_to_le32(4);
3999 pSMB->MaxDataCount = cpu_to_le32(16384);
4000 pSMB->ParameterCount = cpu_to_le32(param_count);
4001 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4002 pSMB->TotalParameterCount = pSMB->ParameterCount;
4003 pSMB->DataOffset = cpu_to_le32(data_offset);
4004 pSMB->SetupCount = 0;
4005 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4006 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4007
4008 pSMB->Fid = fid; /* file handle always le */
4009 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004010 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004011
4012 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004013 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4014 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004015 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004016 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004017 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004018
4019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4021
Joe Perchesf96637b2013-05-04 22:12:25 -05004022 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4023 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004024 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004025 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004026 cifs_buf_release(pSMB);
4027
4028 if (rc == -EAGAIN)
4029 goto setCifsAclRetry;
4030
4031 return (rc);
4032}
4033
Steve French0a4b92c2006-01-12 15:44:21 -08004034
Steve French6b8edfe2005-08-23 20:26:03 -07004035/* Legacy Query Path Information call for lookup to old servers such
4036 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004037int
4038SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4039 const char *search_name, FILE_ALL_INFO *data,
4040 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004041{
Steve Frenchad7a2922008-02-07 23:25:02 +00004042 QUERY_INFORMATION_REQ *pSMB;
4043 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004044 int rc = 0;
4045 int bytes_returned;
4046 int name_len;
4047
Joe Perchesf96637b2013-05-04 22:12:25 -05004048 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004049QInfRetry:
4050 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004051 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004052 if (rc)
4053 return rc;
4054
4055 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4056 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004057 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004058 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004059 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004060 name_len++; /* trailing null */
4061 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004062 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004063 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004064 }
4065 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004066 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004067 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004068 pSMB->ByteCount = cpu_to_le16(name_len);
4069
4070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004072 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004073 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004074 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004075 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004076 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004077
4078 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004079 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004080 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004081 ts.tv_nsec = 0;
4082 ts.tv_sec = time;
4083 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004084 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4085 data->LastWriteTime = data->ChangeTime;
4086 data->LastAccessTime = 0;
4087 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004088 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004089 data->EndOfFile = data->AllocationSize;
4090 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004091 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004092 } else
4093 rc = -EIO; /* bad buffer passed in */
4094
4095 cifs_buf_release(pSMB);
4096
4097 if (rc == -EAGAIN)
4098 goto QInfRetry;
4099
4100 return rc;
4101}
4102
Jeff Laytonbcd53572010-02-12 07:44:16 -05004103int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004104CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004105 u16 netfid, FILE_ALL_INFO *pFindData)
4106{
4107 struct smb_t2_qfi_req *pSMB = NULL;
4108 struct smb_t2_qfi_rsp *pSMBr = NULL;
4109 int rc = 0;
4110 int bytes_returned;
4111 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004112
Jeff Laytonbcd53572010-02-12 07:44:16 -05004113QFileInfoRetry:
4114 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4115 (void **) &pSMBr);
4116 if (rc)
4117 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004118
Jeff Laytonbcd53572010-02-12 07:44:16 -05004119 params = 2 /* level */ + 2 /* fid */;
4120 pSMB->t2.TotalDataCount = 0;
4121 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4122 /* BB find exact max data count below from sess structure BB */
4123 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4124 pSMB->t2.MaxSetupCount = 0;
4125 pSMB->t2.Reserved = 0;
4126 pSMB->t2.Flags = 0;
4127 pSMB->t2.Timeout = 0;
4128 pSMB->t2.Reserved2 = 0;
4129 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4130 Fid) - 4);
4131 pSMB->t2.DataCount = 0;
4132 pSMB->t2.DataOffset = 0;
4133 pSMB->t2.SetupCount = 1;
4134 pSMB->t2.Reserved3 = 0;
4135 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4136 byte_count = params + 1 /* pad */ ;
4137 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4138 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4139 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4140 pSMB->Pad = 0;
4141 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004142 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004143 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004144
4145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4147 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004148 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004149 } else { /* decode response */
4150 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4151
4152 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4153 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004154 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004155 rc = -EIO; /* bad smb */
4156 else if (pFindData) {
4157 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4158 memcpy((char *) pFindData,
4159 (char *) &pSMBr->hdr.Protocol +
4160 data_offset, sizeof(FILE_ALL_INFO));
4161 } else
4162 rc = -ENOMEM;
4163 }
4164 cifs_buf_release(pSMB);
4165 if (rc == -EAGAIN)
4166 goto QFileInfoRetry;
4167
4168 return rc;
4169}
Steve French6b8edfe2005-08-23 20:26:03 -07004170
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004172CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004173 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004174 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004175 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004177 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 TRANSACTION2_QPI_REQ *pSMB = NULL;
4179 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4180 int rc = 0;
4181 int bytes_returned;
4182 int name_len;
4183 __u16 params, byte_count;
4184
Joe Perchesf96637b2013-05-04 22:12:25 -05004185 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186QPathInfoRetry:
4187 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4188 (void **) &pSMBr);
4189 if (rc)
4190 return rc;
4191
4192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4193 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004194 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004195 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 name_len++; /* trailing null */
4197 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004198 } else {
4199 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 }
4201
Steve French50c2f752007-07-13 00:33:32 +00004202 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pSMB->TotalDataCount = 0;
4204 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004205 /* BB find exact max SMB PDU from sess structure BB */
4206 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 pSMB->MaxSetupCount = 0;
4208 pSMB->Reserved = 0;
4209 pSMB->Flags = 0;
4210 pSMB->Timeout = 0;
4211 pSMB->Reserved2 = 0;
4212 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004213 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 pSMB->DataCount = 0;
4215 pSMB->DataOffset = 0;
4216 pSMB->SetupCount = 1;
4217 pSMB->Reserved3 = 0;
4218 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4219 byte_count = params + 1 /* pad */ ;
4220 pSMB->TotalParameterCount = cpu_to_le16(params);
4221 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004222 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004223 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4224 else
4225 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004227 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 pSMB->ByteCount = cpu_to_le16(byte_count);
4229
4230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4232 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004233 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 } else { /* decode response */
4235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4236
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004237 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4238 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004239 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004241 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004242 rc = -EIO; /* 24 or 26 expected but we do not read
4243 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004244 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004245 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004247
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004248 /*
4249 * On legacy responses we do not read the last field,
4250 * EAsize, fortunately since it varies by subdialect and
4251 * also note it differs on Set vs Get, ie two bytes or 4
4252 * bytes depending but we don't care here.
4253 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004254 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004255 size = sizeof(FILE_INFO_STANDARD);
4256 else
4257 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004258 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004259 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 } else
4261 rc = -ENOMEM;
4262 }
4263 cifs_buf_release(pSMB);
4264 if (rc == -EAGAIN)
4265 goto QPathInfoRetry;
4266
4267 return rc;
4268}
4269
4270int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004271CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004272 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4273{
4274 struct smb_t2_qfi_req *pSMB = NULL;
4275 struct smb_t2_qfi_rsp *pSMBr = NULL;
4276 int rc = 0;
4277 int bytes_returned;
4278 __u16 params, byte_count;
4279
4280UnixQFileInfoRetry:
4281 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4282 (void **) &pSMBr);
4283 if (rc)
4284 return rc;
4285
4286 params = 2 /* level */ + 2 /* fid */;
4287 pSMB->t2.TotalDataCount = 0;
4288 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4289 /* BB find exact max data count below from sess structure BB */
4290 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4291 pSMB->t2.MaxSetupCount = 0;
4292 pSMB->t2.Reserved = 0;
4293 pSMB->t2.Flags = 0;
4294 pSMB->t2.Timeout = 0;
4295 pSMB->t2.Reserved2 = 0;
4296 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4297 Fid) - 4);
4298 pSMB->t2.DataCount = 0;
4299 pSMB->t2.DataOffset = 0;
4300 pSMB->t2.SetupCount = 1;
4301 pSMB->t2.Reserved3 = 0;
4302 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4303 byte_count = params + 1 /* pad */ ;
4304 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4305 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4306 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4307 pSMB->Pad = 0;
4308 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004309 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004310 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004311
4312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4314 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004315 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004316 } else { /* decode response */
4317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4318
Jeff Layton820a8032011-05-04 08:05:26 -04004319 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004320 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 -05004321 rc = -EIO; /* bad smb */
4322 } else {
4323 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4324 memcpy((char *) pFindData,
4325 (char *) &pSMBr->hdr.Protocol +
4326 data_offset,
4327 sizeof(FILE_UNIX_BASIC_INFO));
4328 }
4329 }
4330
4331 cifs_buf_release(pSMB);
4332 if (rc == -EAGAIN)
4333 goto UnixQFileInfoRetry;
4334
4335 return rc;
4336}
4337
4338int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004339CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004341 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004342 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343{
4344/* SMB_QUERY_FILE_UNIX_BASIC */
4345 TRANSACTION2_QPI_REQ *pSMB = NULL;
4346 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4347 int rc = 0;
4348 int bytes_returned = 0;
4349 int name_len;
4350 __u16 params, byte_count;
4351
Joe Perchesf96637b2013-05-04 22:12:25 -05004352 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353UnixQPathInfoRetry:
4354 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4355 (void **) &pSMBr);
4356 if (rc)
4357 return rc;
4358
4359 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4360 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004361 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4362 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 name_len++; /* trailing null */
4364 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004365 } else {
4366 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 }
4368
Steve French50c2f752007-07-13 00:33:32 +00004369 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 pSMB->TotalDataCount = 0;
4371 pSMB->MaxParameterCount = cpu_to_le16(2);
4372 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004373 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 pSMB->MaxSetupCount = 0;
4375 pSMB->Reserved = 0;
4376 pSMB->Flags = 0;
4377 pSMB->Timeout = 0;
4378 pSMB->Reserved2 = 0;
4379 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004380 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 pSMB->DataCount = 0;
4382 pSMB->DataOffset = 0;
4383 pSMB->SetupCount = 1;
4384 pSMB->Reserved3 = 0;
4385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4386 byte_count = params + 1 /* pad */ ;
4387 pSMB->TotalParameterCount = cpu_to_le16(params);
4388 pSMB->ParameterCount = pSMB->TotalParameterCount;
4389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4390 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004391 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 pSMB->ByteCount = cpu_to_le16(byte_count);
4393
4394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4396 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004397 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 } else { /* decode response */
4399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4400
Jeff Layton820a8032011-05-04 08:05:26 -04004401 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004402 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 -07004403 rc = -EIO; /* bad smb */
4404 } else {
4405 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4406 memcpy((char *) pFindData,
4407 (char *) &pSMBr->hdr.Protocol +
4408 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004409 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 }
4411 }
4412 cifs_buf_release(pSMB);
4413 if (rc == -EAGAIN)
4414 goto UnixQPathInfoRetry;
4415
4416 return rc;
4417}
4418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419/* xid, tcon, searchName and codepage are input parms, rest are returned */
4420int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004421CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004422 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004423 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004424 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425{
4426/* level 257 SMB_ */
4427 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4428 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004429 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 int rc = 0;
4431 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004432 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004434 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Joe Perchesf96637b2013-05-04 22:12:25 -05004436 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437
4438findFirstRetry:
4439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4440 (void **) &pSMBr);
4441 if (rc)
4442 return rc;
4443
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004444 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004445 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004446
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4448 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004449 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4450 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004451 /* We can not add the asterik earlier in case
4452 it got remapped to 0xF03A as if it were part of the
4453 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004455 if (msearch) {
4456 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4457 pSMB->FileName[name_len+1] = 0;
4458 pSMB->FileName[name_len+2] = '*';
4459 pSMB->FileName[name_len+3] = 0;
4460 name_len += 4; /* now the trailing null */
4461 /* null terminate just in case */
4462 pSMB->FileName[name_len] = 0;
4463 pSMB->FileName[name_len+1] = 0;
4464 name_len += 2;
4465 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004466 } else {
4467 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004468 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004469 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4470 name_len = PATH_MAX-2;
4471 /* overwrite nul byte */
4472 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4473 pSMB->FileName[name_len] = '*';
4474 pSMB->FileName[name_len+1] = 0;
4475 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 }
4478
4479 params = 12 + name_len /* includes null */ ;
4480 pSMB->TotalDataCount = 0; /* no EAs */
4481 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004482 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 pSMB->MaxSetupCount = 0;
4484 pSMB->Reserved = 0;
4485 pSMB->Flags = 0;
4486 pSMB->Timeout = 0;
4487 pSMB->Reserved2 = 0;
4488 byte_count = params + 1 /* pad */ ;
4489 pSMB->TotalParameterCount = cpu_to_le16(params);
4490 pSMB->ParameterCount = pSMB->TotalParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004492 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4493 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 pSMB->DataCount = 0;
4495 pSMB->DataOffset = 0;
4496 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4497 pSMB->Reserved3 = 0;
4498 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4499 pSMB->SearchAttributes =
4500 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4501 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004502 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004503 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4505
4506 /* BB what should we set StorageType to? Does it matter? BB */
4507 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004508 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 pSMB->ByteCount = cpu_to_le16(byte_count);
4510
4511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4512 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004513 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
Steve French88274812006-03-09 22:21:45 +00004515 if (rc) {/* BB add logic to retry regular search if Unix search
4516 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004518 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004519
Steve French88274812006-03-09 22:21:45 +00004520 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521
4522 /* BB eventually could optimize out free and realloc of buf */
4523 /* for this case */
4524 if (rc == -EAGAIN)
4525 goto findFirstRetry;
4526 } else { /* decode response */
4527 /* BB remember to free buffer if error BB */
4528 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004529 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004530 unsigned int lnoff;
4531
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004533 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 else
Steve French4b18f2a2008-04-29 00:06:05 +00004535 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
4537 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004538 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004539 psrch_inf->srch_entries_start =
4540 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4543 le16_to_cpu(pSMBr->t2.ParameterOffset));
4544
Steve French790fe572007-07-07 19:25:05 +00004545 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004546 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 else
Steve French4b18f2a2008-04-29 00:06:05 +00004548 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Steve French50c2f752007-07-13 00:33:32 +00004550 psrch_inf->entries_in_buffer =
4551 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004552 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004554 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004555 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004556 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004557 psrch_inf->last_entry = NULL;
4558 return rc;
4559 }
4560
Steve French0752f152008-10-07 20:03:33 +00004561 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004562 lnoff;
4563
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004564 if (pnetfid)
4565 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 } else {
4567 cifs_buf_release(pSMB);
4568 }
4569 }
4570
4571 return rc;
4572}
4573
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004574int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4575 __u16 searchHandle, __u16 search_flags,
4576 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577{
4578 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4579 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004580 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 char *response_data;
4582 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004583 int bytes_returned;
4584 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 __u16 params, byte_count;
4586
Joe Perchesf96637b2013-05-04 22:12:25 -05004587 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Steve French4b18f2a2008-04-29 00:06:05 +00004589 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 return -ENOENT;
4591
4592 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4593 (void **) &pSMBr);
4594 if (rc)
4595 return rc;
4596
Steve French50c2f752007-07-13 00:33:32 +00004597 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 byte_count = 0;
4599 pSMB->TotalDataCount = 0; /* no EAs */
4600 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004601 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 pSMB->ParameterOffset = cpu_to_le16(
4608 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4609 pSMB->DataCount = 0;
4610 pSMB->DataOffset = 0;
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4614 pSMB->SearchHandle = searchHandle; /* always kept as le */
4615 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004616 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4618 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004619 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
4621 name_len = psrch_inf->resume_name_len;
4622 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004623 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4625 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004626 /* 14 byte parm len above enough for 2 byte null terminator */
4627 pSMB->ResumeFileName[name_len] = 0;
4628 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 } else {
4630 rc = -EINVAL;
4631 goto FNext2_err_exit;
4632 }
4633 byte_count = params + 1 /* pad */ ;
4634 pSMB->TotalParameterCount = cpu_to_le16(params);
4635 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004636 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004638
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004641 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 if (rc) {
4643 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004644 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004645 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004646 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004648 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 } else { /* decode response */
4650 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004651
Steve French790fe572007-07-07 19:25:05 +00004652 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004653 unsigned int lnoff;
4654
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 /* BB fixme add lock for file (srch_info) struct here */
4656 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004657 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 else
Steve French4b18f2a2008-04-29 00:06:05 +00004659 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 response_data = (char *) &pSMBr->hdr.Protocol +
4661 le16_to_cpu(pSMBr->t2.ParameterOffset);
4662 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4663 response_data = (char *)&pSMBr->hdr.Protocol +
4664 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004665 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004666 cifs_small_buf_release(
4667 psrch_inf->ntwrk_buf_start);
4668 else
4669 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 psrch_inf->srch_entries_start = response_data;
4671 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004672 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004673 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004674 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 else
Steve French4b18f2a2008-04-29 00:06:05 +00004676 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004677 psrch_inf->entries_in_buffer =
4678 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 psrch_inf->index_of_last_entry +=
4680 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004681 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004682 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004683 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004684 psrch_inf->last_entry = NULL;
4685 return rc;
4686 } else
4687 psrch_inf->last_entry =
4688 psrch_inf->srch_entries_start + lnoff;
4689
Joe Perchesf96637b2013-05-04 22:12:25 -05004690/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4691 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
4693 /* BB fixme add unlock here */
4694 }
4695
4696 }
4697
4698 /* BB On error, should we leave previous search buf (and count and
4699 last entry fields) intact or free the previous one? */
4700
4701 /* Note: On -EAGAIN error only caller can retry on handle based calls
4702 since file handle passed in no longer valid */
4703FNext2_err_exit:
4704 if (rc != 0)
4705 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 return rc;
4707}
4708
4709int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004710CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004711 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712{
4713 int rc = 0;
4714 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
Joe Perchesf96637b2013-05-04 22:12:25 -05004716 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4718
4719 /* no sense returning error if session restarted
4720 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004721 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 return 0;
4723 if (rc)
4724 return rc;
4725
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 pSMB->FileID = searchHandle;
4727 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004728 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004729 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004730 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004731 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004732
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004733 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734
4735 /* Since session is dead, search handle closed on server already */
4736 if (rc == -EAGAIN)
4737 rc = 0;
4738
4739 return rc;
4740}
4741
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004743CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004744 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004745 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746{
4747 int rc = 0;
4748 TRANSACTION2_QPI_REQ *pSMB = NULL;
4749 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4750 int name_len, bytes_returned;
4751 __u16 params, byte_count;
4752
Joe Perchesf96637b2013-05-04 22:12:25 -05004753 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004754 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004755 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
4757GetInodeNumberRetry:
4758 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004759 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 if (rc)
4761 return rc;
4762
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4764 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004765 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004766 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004767 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 name_len++; /* trailing null */
4769 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004770 } else {
4771 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 }
4773
4774 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4775 pSMB->TotalDataCount = 0;
4776 pSMB->MaxParameterCount = cpu_to_le16(2);
4777 /* BB find exact max data count below from sess structure BB */
4778 pSMB->MaxDataCount = cpu_to_le16(4000);
4779 pSMB->MaxSetupCount = 0;
4780 pSMB->Reserved = 0;
4781 pSMB->Flags = 0;
4782 pSMB->Timeout = 0;
4783 pSMB->Reserved2 = 0;
4784 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004785 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->DataCount = 0;
4787 pSMB->DataOffset = 0;
4788 pSMB->SetupCount = 1;
4789 pSMB->Reserved3 = 0;
4790 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4791 byte_count = params + 1 /* pad */ ;
4792 pSMB->TotalParameterCount = cpu_to_le16(params);
4793 pSMB->ParameterCount = pSMB->TotalParameterCount;
4794 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4795 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004796 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->ByteCount = cpu_to_le16(byte_count);
4798
4799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4801 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004802 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 } else {
4804 /* decode response */
4805 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004807 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 /* If rc should we check for EOPNOSUPP and
4809 disable the srvino flag? or in caller? */
4810 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004811 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4813 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004814 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004816 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004817 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 rc = -EIO;
4819 goto GetInodeNumOut;
4820 }
4821 pfinfo = (struct file_internal_info *)
4822 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004823 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 }
4825 }
4826GetInodeNumOut:
4827 cifs_buf_release(pSMB);
4828 if (rc == -EAGAIN)
4829 goto GetInodeNumberRetry;
4830 return rc;
4831}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832
4833int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004834CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004835 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004836 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004837 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
4839/* TRANS2_GET_DFS_REFERRAL */
4840 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4841 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 int rc = 0;
4843 int bytes_returned;
4844 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004846 *num_of_nodes = 0;
4847 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848
Joe Perchesf96637b2013-05-04 22:12:25 -05004849 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004850 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004852
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004854 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 (void **) &pSMBr);
4856 if (rc)
4857 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004858
4859 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004860 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004861 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004862 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004864 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004866 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868
4869 if (ses->capabilities & CAP_UNICODE) {
4870 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4871 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004872 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004873 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004874 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 name_len++; /* trailing null */
4876 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004877 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004878 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 }
4880
Dan Carpenter65c3b202015-04-30 17:30:24 +03004881 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004882 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004883
Steve French50c2f752007-07-13 00:33:32 +00004884 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004885
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 params = 2 /* level */ + name_len /*includes null */ ;
4887 pSMB->TotalDataCount = 0;
4888 pSMB->DataCount = 0;
4889 pSMB->DataOffset = 0;
4890 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004891 /* BB find exact max SMB PDU from sess structure BB */
4892 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 pSMB->MaxSetupCount = 0;
4894 pSMB->Reserved = 0;
4895 pSMB->Flags = 0;
4896 pSMB->Timeout = 0;
4897 pSMB->Reserved2 = 0;
4898 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004899 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 pSMB->SetupCount = 1;
4901 pSMB->Reserved3 = 0;
4902 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4903 byte_count = params + 3 /* pad */ ;
4904 pSMB->ParameterCount = cpu_to_le16(params);
4905 pSMB->TotalParameterCount = pSMB->ParameterCount;
4906 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004907 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 pSMB->ByteCount = cpu_to_le16(byte_count);
4909
4910 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4912 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004913 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004914 goto GetDFSRefExit;
4915 }
4916 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004918 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004919 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004920 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004921 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004923
Joe Perchesf96637b2013-05-04 22:12:25 -05004924 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4925 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004926
4927 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004928 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4929 le16_to_cpu(pSMBr->t2.DataCount),
4930 num_of_nodes, target_nodes, nls_codepage,
4931 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004932 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004933
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004935 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
4937 if (rc == -EAGAIN)
4938 goto getDFSRetry;
4939
4940 return rc;
4941}
4942
Steve French20962432005-09-21 22:05:57 -07004943/* Query File System Info such as free space to old servers such as Win 9x */
4944int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004945SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4946 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004947{
4948/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4949 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4950 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4951 FILE_SYSTEM_ALLOC_INFO *response_data;
4952 int rc = 0;
4953 int bytes_returned = 0;
4954 __u16 params, byte_count;
4955
Joe Perchesf96637b2013-05-04 22:12:25 -05004956 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004957oldQFSInfoRetry:
4958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4959 (void **) &pSMBr);
4960 if (rc)
4961 return rc;
Steve French20962432005-09-21 22:05:57 -07004962
4963 params = 2; /* level */
4964 pSMB->TotalDataCount = 0;
4965 pSMB->MaxParameterCount = cpu_to_le16(2);
4966 pSMB->MaxDataCount = cpu_to_le16(1000);
4967 pSMB->MaxSetupCount = 0;
4968 pSMB->Reserved = 0;
4969 pSMB->Flags = 0;
4970 pSMB->Timeout = 0;
4971 pSMB->Reserved2 = 0;
4972 byte_count = params + 1 /* pad */ ;
4973 pSMB->TotalParameterCount = cpu_to_le16(params);
4974 pSMB->ParameterCount = pSMB->TotalParameterCount;
4975 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4976 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4977 pSMB->DataCount = 0;
4978 pSMB->DataOffset = 0;
4979 pSMB->SetupCount = 1;
4980 pSMB->Reserved3 = 0;
4981 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4982 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004983 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004984 pSMB->ByteCount = cpu_to_le16(byte_count);
4985
4986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4988 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004989 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004990 } else { /* decode response */
4991 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4992
Jeff Layton820a8032011-05-04 08:05:26 -04004993 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004994 rc = -EIO; /* bad smb */
4995 else {
4996 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004997 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004998 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004999
Steve French50c2f752007-07-13 00:33:32 +00005000 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005001 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5002 FSData->f_bsize =
5003 le16_to_cpu(response_data->BytesPerSector) *
5004 le32_to_cpu(response_data->
5005 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005006 /*
5007 * much prefer larger but if server doesn't report
5008 * a valid size than 4K is a reasonable minimum
5009 */
5010 if (FSData->f_bsize < 512)
5011 FSData->f_bsize = 4096;
5012
Steve French20962432005-09-21 22:05:57 -07005013 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005014 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005015 FSData->f_bfree = FSData->f_bavail =
5016 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005017 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5018 (unsigned long long)FSData->f_blocks,
5019 (unsigned long long)FSData->f_bfree,
5020 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005021 }
5022 }
5023 cifs_buf_release(pSMB);
5024
5025 if (rc == -EAGAIN)
5026 goto oldQFSInfoRetry;
5027
5028 return rc;
5029}
5030
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005032CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5033 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034{
5035/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5036 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5037 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5038 FILE_SYSTEM_INFO *response_data;
5039 int rc = 0;
5040 int bytes_returned = 0;
5041 __u16 params, byte_count;
5042
Joe Perchesf96637b2013-05-04 22:12:25 -05005043 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044QFSInfoRetry:
5045 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5046 (void **) &pSMBr);
5047 if (rc)
5048 return rc;
5049
5050 params = 2; /* level */
5051 pSMB->TotalDataCount = 0;
5052 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005053 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 pSMB->MaxSetupCount = 0;
5055 pSMB->Reserved = 0;
5056 pSMB->Flags = 0;
5057 pSMB->Timeout = 0;
5058 pSMB->Reserved2 = 0;
5059 byte_count = params + 1 /* pad */ ;
5060 pSMB->TotalParameterCount = cpu_to_le16(params);
5061 pSMB->ParameterCount = pSMB->TotalParameterCount;
5062 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005063 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 pSMB->DataCount = 0;
5065 pSMB->DataOffset = 0;
5066 pSMB->SetupCount = 1;
5067 pSMB->Reserved3 = 0;
5068 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5069 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 pSMB->ByteCount = cpu_to_le16(byte_count);
5072
5073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5075 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005076 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
Jeff Layton820a8032011-05-04 08:05:26 -04005080 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 rc = -EIO; /* bad smb */
5082 else {
5083 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084
5085 response_data =
5086 (FILE_SYSTEM_INFO
5087 *) (((char *) &pSMBr->hdr.Protocol) +
5088 data_offset);
5089 FSData->f_bsize =
5090 le32_to_cpu(response_data->BytesPerSector) *
5091 le32_to_cpu(response_data->
5092 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005093 /*
5094 * much prefer larger but if server doesn't report
5095 * a valid size than 4K is a reasonable minimum
5096 */
5097 if (FSData->f_bsize < 512)
5098 FSData->f_bsize = 4096;
5099
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 FSData->f_blocks =
5101 le64_to_cpu(response_data->TotalAllocationUnits);
5102 FSData->f_bfree = FSData->f_bavail =
5103 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005104 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5105 (unsigned long long)FSData->f_blocks,
5106 (unsigned long long)FSData->f_bfree,
5107 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 }
5109 }
5110 cifs_buf_release(pSMB);
5111
5112 if (rc == -EAGAIN)
5113 goto QFSInfoRetry;
5114
5115 return rc;
5116}
5117
5118int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005119CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120{
5121/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5122 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5123 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5124 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5125 int rc = 0;
5126 int bytes_returned = 0;
5127 __u16 params, byte_count;
5128
Joe Perchesf96637b2013-05-04 22:12:25 -05005129 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130QFSAttributeRetry:
5131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5132 (void **) &pSMBr);
5133 if (rc)
5134 return rc;
5135
5136 params = 2; /* level */
5137 pSMB->TotalDataCount = 0;
5138 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005139 /* BB find exact max SMB PDU from sess structure BB */
5140 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 pSMB->MaxSetupCount = 0;
5142 pSMB->Reserved = 0;
5143 pSMB->Flags = 0;
5144 pSMB->Timeout = 0;
5145 pSMB->Reserved2 = 0;
5146 byte_count = params + 1 /* pad */ ;
5147 pSMB->TotalParameterCount = cpu_to_le16(params);
5148 pSMB->ParameterCount = pSMB->TotalParameterCount;
5149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005150 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pSMB->DataCount = 0;
5152 pSMB->DataOffset = 0;
5153 pSMB->SetupCount = 1;
5154 pSMB->Reserved3 = 0;
5155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5156 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005157 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 pSMB->ByteCount = cpu_to_le16(byte_count);
5159
5160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5162 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005163 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 } else { /* decode response */
5165 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5166
Jeff Layton820a8032011-05-04 08:05:26 -04005167 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005168 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 rc = -EIO; /* bad smb */
5170 } else {
5171 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5172 response_data =
5173 (FILE_SYSTEM_ATTRIBUTE_INFO
5174 *) (((char *) &pSMBr->hdr.Protocol) +
5175 data_offset);
5176 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005177 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 }
5179 }
5180 cifs_buf_release(pSMB);
5181
5182 if (rc == -EAGAIN)
5183 goto QFSAttributeRetry;
5184
5185 return rc;
5186}
5187
5188int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005189CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190{
5191/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5192 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5193 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5194 FILE_SYSTEM_DEVICE_INFO *response_data;
5195 int rc = 0;
5196 int bytes_returned = 0;
5197 __u16 params, byte_count;
5198
Joe Perchesf96637b2013-05-04 22:12:25 -05005199 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200QFSDeviceRetry:
5201 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5202 (void **) &pSMBr);
5203 if (rc)
5204 return rc;
5205
5206 params = 2; /* level */
5207 pSMB->TotalDataCount = 0;
5208 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005209 /* BB find exact max SMB PDU from sess structure BB */
5210 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 pSMB->MaxSetupCount = 0;
5212 pSMB->Reserved = 0;
5213 pSMB->Flags = 0;
5214 pSMB->Timeout = 0;
5215 pSMB->Reserved2 = 0;
5216 byte_count = params + 1 /* pad */ ;
5217 pSMB->TotalParameterCount = cpu_to_le16(params);
5218 pSMB->ParameterCount = pSMB->TotalParameterCount;
5219 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005220 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221
5222 pSMB->DataCount = 0;
5223 pSMB->DataOffset = 0;
5224 pSMB->SetupCount = 1;
5225 pSMB->Reserved3 = 0;
5226 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5227 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005228 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 pSMB->ByteCount = cpu_to_le16(byte_count);
5230
5231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5233 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005234 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 } else { /* decode response */
5236 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5237
Jeff Layton820a8032011-05-04 08:05:26 -04005238 if (rc || get_bcc(&pSMBr->hdr) <
5239 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 rc = -EIO; /* bad smb */
5241 else {
5242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5243 response_data =
Steve French737b7582005-04-28 22:41:06 -07005244 (FILE_SYSTEM_DEVICE_INFO *)
5245 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 data_offset);
5247 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005248 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 }
5250 }
5251 cifs_buf_release(pSMB);
5252
5253 if (rc == -EAGAIN)
5254 goto QFSDeviceRetry;
5255
5256 return rc;
5257}
5258
5259int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005260CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261{
5262/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5263 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5264 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5265 FILE_SYSTEM_UNIX_INFO *response_data;
5266 int rc = 0;
5267 int bytes_returned = 0;
5268 __u16 params, byte_count;
5269
Joe Perchesf96637b2013-05-04 22:12:25 -05005270 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005272 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5273 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 if (rc)
5275 return rc;
5276
5277 params = 2; /* level */
5278 pSMB->TotalDataCount = 0;
5279 pSMB->DataCount = 0;
5280 pSMB->DataOffset = 0;
5281 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005282 /* BB find exact max SMB PDU from sess structure BB */
5283 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 pSMB->MaxSetupCount = 0;
5285 pSMB->Reserved = 0;
5286 pSMB->Flags = 0;
5287 pSMB->Timeout = 0;
5288 pSMB->Reserved2 = 0;
5289 byte_count = params + 1 /* pad */ ;
5290 pSMB->ParameterCount = cpu_to_le16(params);
5291 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005292 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5293 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pSMB->SetupCount = 1;
5295 pSMB->Reserved3 = 0;
5296 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5297 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005298 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 pSMB->ByteCount = cpu_to_le16(byte_count);
5300
5301 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5302 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5303 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005304 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 } else { /* decode response */
5306 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5307
Jeff Layton820a8032011-05-04 08:05:26 -04005308 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 rc = -EIO; /* bad smb */
5310 } else {
5311 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5312 response_data =
5313 (FILE_SYSTEM_UNIX_INFO
5314 *) (((char *) &pSMBr->hdr.Protocol) +
5315 data_offset);
5316 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005317 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 }
5319 }
5320 cifs_buf_release(pSMB);
5321
5322 if (rc == -EAGAIN)
5323 goto QFSUnixRetry;
5324
5325
5326 return rc;
5327}
5328
Jeremy Allisonac670552005-06-22 17:26:35 -07005329int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005330CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005331{
5332/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5333 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5334 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5335 int rc = 0;
5336 int bytes_returned = 0;
5337 __u16 params, param_offset, offset, byte_count;
5338
Joe Perchesf96637b2013-05-04 22:12:25 -05005339 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005340SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005341 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005342 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5343 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005344 if (rc)
5345 return rc;
5346
5347 params = 4; /* 2 bytes zero followed by info level. */
5348 pSMB->MaxSetupCount = 0;
5349 pSMB->Reserved = 0;
5350 pSMB->Flags = 0;
5351 pSMB->Timeout = 0;
5352 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005353 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5354 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005355 offset = param_offset + params;
5356
5357 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005358 /* BB find exact max SMB PDU from sess structure BB */
5359 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005360 pSMB->SetupCount = 1;
5361 pSMB->Reserved3 = 0;
5362 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5363 byte_count = 1 /* pad */ + params + 12;
5364
5365 pSMB->DataCount = cpu_to_le16(12);
5366 pSMB->ParameterCount = cpu_to_le16(params);
5367 pSMB->TotalDataCount = pSMB->DataCount;
5368 pSMB->TotalParameterCount = pSMB->ParameterCount;
5369 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5370 pSMB->DataOffset = cpu_to_le16(offset);
5371
5372 /* Params. */
5373 pSMB->FileNum = 0;
5374 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5375
5376 /* Data. */
5377 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5378 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5379 pSMB->ClientUnixCap = cpu_to_le64(cap);
5380
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005381 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005382 pSMB->ByteCount = cpu_to_le16(byte_count);
5383
5384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5386 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005387 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005388 } else { /* decode response */
5389 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005390 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005391 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005392 }
5393 cifs_buf_release(pSMB);
5394
5395 if (rc == -EAGAIN)
5396 goto SETFSUnixRetry;
5397
5398 return rc;
5399}
5400
5401
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
5403int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005404CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005405 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406{
5407/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5408 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5409 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5410 FILE_SYSTEM_POSIX_INFO *response_data;
5411 int rc = 0;
5412 int bytes_returned = 0;
5413 __u16 params, byte_count;
5414
Joe Perchesf96637b2013-05-04 22:12:25 -05005415 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416QFSPosixRetry:
5417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5418 (void **) &pSMBr);
5419 if (rc)
5420 return rc;
5421
5422 params = 2; /* level */
5423 pSMB->TotalDataCount = 0;
5424 pSMB->DataCount = 0;
5425 pSMB->DataOffset = 0;
5426 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005427 /* BB find exact max SMB PDU from sess structure BB */
5428 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 pSMB->MaxSetupCount = 0;
5430 pSMB->Reserved = 0;
5431 pSMB->Flags = 0;
5432 pSMB->Timeout = 0;
5433 pSMB->Reserved2 = 0;
5434 byte_count = params + 1 /* pad */ ;
5435 pSMB->ParameterCount = cpu_to_le16(params);
5436 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005437 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5438 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 pSMB->SetupCount = 1;
5440 pSMB->Reserved3 = 0;
5441 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5442 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005443 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 pSMB->ByteCount = cpu_to_le16(byte_count);
5445
5446 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5447 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5448 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005449 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 } else { /* decode response */
5451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5452
Jeff Layton820a8032011-05-04 08:05:26 -04005453 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 rc = -EIO; /* bad smb */
5455 } else {
5456 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5457 response_data =
5458 (FILE_SYSTEM_POSIX_INFO
5459 *) (((char *) &pSMBr->hdr.Protocol) +
5460 data_offset);
5461 FSData->f_bsize =
5462 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005463 /*
5464 * much prefer larger but if server doesn't report
5465 * a valid size than 4K is a reasonable minimum
5466 */
5467 if (FSData->f_bsize < 512)
5468 FSData->f_bsize = 4096;
5469
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 FSData->f_blocks =
5471 le64_to_cpu(response_data->TotalBlocks);
5472 FSData->f_bfree =
5473 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005474 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 FSData->f_bavail = FSData->f_bfree;
5476 } else {
5477 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005478 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 }
Steve French790fe572007-07-07 19:25:05 +00005480 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005482 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005483 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005485 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 }
5487 }
5488 cifs_buf_release(pSMB);
5489
5490 if (rc == -EAGAIN)
5491 goto QFSPosixRetry;
5492
5493 return rc;
5494}
5495
5496
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005497/*
5498 * We can not use write of zero bytes trick to set file size due to need for
5499 * large file support. Also note that this SetPathInfo is preferred to
5500 * SetFileInfo based method in next routine which is only needed to work around
5501 * a sharing violation bugin Samba which this routine can run into.
5502 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005504CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005505 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5506 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507{
5508 struct smb_com_transaction2_spi_req *pSMB = NULL;
5509 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5510 struct file_end_of_file_info *parm_data;
5511 int name_len;
5512 int rc = 0;
5513 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005514 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005515
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 __u16 params, byte_count, data_count, param_offset, offset;
5517
Joe Perchesf96637b2013-05-04 22:12:25 -05005518 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519SetEOFRetry:
5520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5521 (void **) &pSMBr);
5522 if (rc)
5523 return rc;
5524
5525 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5526 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005527 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5528 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 name_len++; /* trailing null */
5530 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005531 } else {
5532 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 }
5534 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005535 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005537 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 pSMB->MaxSetupCount = 0;
5539 pSMB->Reserved = 0;
5540 pSMB->Flags = 0;
5541 pSMB->Timeout = 0;
5542 pSMB->Reserved2 = 0;
5543 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005544 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005546 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005547 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5548 pSMB->InformationLevel =
5549 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5550 else
5551 pSMB->InformationLevel =
5552 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5553 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5555 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005556 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 else
5558 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005559 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 }
5561
5562 parm_data =
5563 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5564 offset);
5565 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5566 pSMB->DataOffset = cpu_to_le16(offset);
5567 pSMB->SetupCount = 1;
5568 pSMB->Reserved3 = 0;
5569 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5570 byte_count = 3 /* pad */ + params + data_count;
5571 pSMB->DataCount = cpu_to_le16(data_count);
5572 pSMB->TotalDataCount = pSMB->DataCount;
5573 pSMB->ParameterCount = cpu_to_le16(params);
5574 pSMB->TotalParameterCount = pSMB->ParameterCount;
5575 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005576 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 parm_data->FileSize = cpu_to_le64(size);
5578 pSMB->ByteCount = cpu_to_le16(byte_count);
5579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005581 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005582 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
5584 cifs_buf_release(pSMB);
5585
5586 if (rc == -EAGAIN)
5587 goto SetEOFRetry;
5588
5589 return rc;
5590}
5591
5592int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005593CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5594 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595{
5596 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 struct file_end_of_file_info *parm_data;
5598 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 __u16 params, param_offset, offset, byte_count, count;
5600
Joe Perchesf96637b2013-05-04 22:12:25 -05005601 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5602 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005603 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5604
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 if (rc)
5606 return rc;
5607
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005608 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5609 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005610
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 params = 6;
5612 pSMB->MaxSetupCount = 0;
5613 pSMB->Reserved = 0;
5614 pSMB->Flags = 0;
5615 pSMB->Timeout = 0;
5616 pSMB->Reserved2 = 0;
5617 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5618 offset = param_offset + params;
5619
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 count = sizeof(struct file_end_of_file_info);
5621 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005622 /* BB find exact max SMB PDU from sess structure BB */
5623 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pSMB->SetupCount = 1;
5625 pSMB->Reserved3 = 0;
5626 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5627 byte_count = 3 /* pad */ + params + count;
5628 pSMB->DataCount = cpu_to_le16(count);
5629 pSMB->ParameterCount = cpu_to_le16(params);
5630 pSMB->TotalDataCount = pSMB->DataCount;
5631 pSMB->TotalParameterCount = pSMB->ParameterCount;
5632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve Frenche3973ea2021-07-06 21:27:26 -05005633 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 parm_data =
Steve Frenche3973ea2021-07-06 21:27:26 -05005635 (struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 pSMB->DataOffset = cpu_to_le16(offset);
5637 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005638 pSMB->Fid = cfile->fid.netfid;
5639 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5641 pSMB->InformationLevel =
5642 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5643 else
5644 pSMB->InformationLevel =
5645 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005646 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5648 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005649 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 else
5651 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005652 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 }
5654 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005655 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005657 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005658 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005660 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5661 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 }
5663
Steve French50c2f752007-07-13 00:33:32 +00005664 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 since file handle passed in no longer valid */
5666
5667 return rc;
5668}
5669
Steve French50c2f752007-07-13 00:33:32 +00005670/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 an open handle, rather than by pathname - this is awkward due to
5672 potential access conflicts on the open, but it is unavoidable for these
5673 old servers since the only other choice is to go from 100 nanosecond DCE
5674 time and resort to the original setpathinfo level which takes the ancient
5675 DOS time format with 2 second granularity */
5676int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005677CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005678 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679{
5680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 char *data_offset;
5682 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 __u16 params, param_offset, offset, byte_count, count;
5684
Joe Perchesf96637b2013-05-04 22:12:25 -05005685 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 if (rc)
5689 return rc;
5690
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005691 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5692 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005693
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 params = 6;
5695 pSMB->MaxSetupCount = 0;
5696 pSMB->Reserved = 0;
5697 pSMB->Flags = 0;
5698 pSMB->Timeout = 0;
5699 pSMB->Reserved2 = 0;
5700 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5701 offset = param_offset + params;
5702
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005703 data_offset = (char *)pSMB +
5704 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705
Steve French26f57362007-08-30 22:09:15 +00005706 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005708 /* BB find max SMB PDU from sess */
5709 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 pSMB->SetupCount = 1;
5711 pSMB->Reserved3 = 0;
5712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5713 byte_count = 3 /* pad */ + params + count;
5714 pSMB->DataCount = cpu_to_le16(count);
5715 pSMB->ParameterCount = cpu_to_le16(params);
5716 pSMB->TotalDataCount = pSMB->DataCount;
5717 pSMB->TotalParameterCount = pSMB->ParameterCount;
5718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5719 pSMB->DataOffset = cpu_to_le16(offset);
5720 pSMB->Fid = fid;
5721 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5722 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5723 else
5724 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5725 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005726 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005728 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005729 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005730 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005731 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005732 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5733 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734
Steve French50c2f752007-07-13 00:33:32 +00005735 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 since file handle passed in no longer valid */
5737
5738 return rc;
5739}
5740
Jeff Layton6d22f092008-09-23 11:48:35 -04005741int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005742CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005743 bool delete_file, __u16 fid, __u32 pid_of_opener)
5744{
5745 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5746 char *data_offset;
5747 int rc = 0;
5748 __u16 params, param_offset, offset, byte_count, count;
5749
Joe Perchesf96637b2013-05-04 22:12:25 -05005750 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005751 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5752
5753 if (rc)
5754 return rc;
5755
5756 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5757 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5758
5759 params = 6;
5760 pSMB->MaxSetupCount = 0;
5761 pSMB->Reserved = 0;
5762 pSMB->Flags = 0;
5763 pSMB->Timeout = 0;
5764 pSMB->Reserved2 = 0;
5765 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5766 offset = param_offset + params;
5767
Steve French2a780e82021-07-06 21:42:08 -05005768 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5769 data_offset = (char *)(pSMB) + offset + 4;
Jeff Layton6d22f092008-09-23 11:48:35 -04005770
5771 count = 1;
5772 pSMB->MaxParameterCount = cpu_to_le16(2);
5773 /* BB find max SMB PDU from sess */
5774 pSMB->MaxDataCount = cpu_to_le16(1000);
5775 pSMB->SetupCount = 1;
5776 pSMB->Reserved3 = 0;
5777 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5778 byte_count = 3 /* pad */ + params + count;
5779 pSMB->DataCount = cpu_to_le16(count);
5780 pSMB->ParameterCount = cpu_to_le16(params);
5781 pSMB->TotalDataCount = pSMB->DataCount;
5782 pSMB->TotalParameterCount = pSMB->ParameterCount;
5783 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5784 pSMB->DataOffset = cpu_to_le16(offset);
5785 pSMB->Fid = fid;
5786 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5787 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005788 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005789 pSMB->ByteCount = cpu_to_le16(byte_count);
5790 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005791 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005792 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005793 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005794 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005795
5796 return rc;
5797}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005799static int
5800CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5801 const char *fileName, const FILE_BASIC_INFO *data,
5802 const struct nls_table *nls_codepage,
5803 struct cifs_sb_info *cifs_sb)
5804{
5805 int oplock = 0;
5806 struct cifs_open_parms oparms;
5807 struct cifs_fid fid;
5808 int rc;
5809
5810 oparms.tcon = tcon;
5811 oparms.cifs_sb = cifs_sb;
5812 oparms.desired_access = GENERIC_WRITE;
5813 oparms.create_options = cifs_create_options(cifs_sb, 0);
5814 oparms.disposition = FILE_OPEN;
5815 oparms.path = fileName;
5816 oparms.fid = &fid;
5817 oparms.reconnect = false;
5818
5819 rc = CIFS_open(xid, &oparms, &oplock, NULL);
5820 if (rc)
5821 goto out;
5822
5823 rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5824 CIFSSMBClose(xid, tcon, fid.netfid);
5825out:
5826
5827 return rc;
5828}
5829
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005831CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005832 const char *fileName, const FILE_BASIC_INFO *data,
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005833 const struct nls_table *nls_codepage,
5834 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835{
5836 TRANSACTION2_SPI_REQ *pSMB = NULL;
5837 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5838 int name_len;
5839 int rc = 0;
5840 int bytes_returned = 0;
5841 char *data_offset;
5842 __u16 params, param_offset, offset, byte_count, count;
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005843 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844
Joe Perchesf96637b2013-05-04 22:12:25 -05005845 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
5847SetTimesRetry:
5848 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5849 (void **) &pSMBr);
5850 if (rc)
5851 return rc;
5852
5853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5854 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005855 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5856 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 name_len++; /* trailing null */
5858 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005859 } else {
5860 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 }
5862
5863 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005864 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005866 /* BB find max SMB PDU from sess structure BB */
5867 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 pSMB->MaxSetupCount = 0;
5869 pSMB->Reserved = 0;
5870 pSMB->Flags = 0;
5871 pSMB->Timeout = 0;
5872 pSMB->Reserved2 = 0;
5873 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005874 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 offset = param_offset + params;
5876 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5877 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5878 pSMB->DataOffset = cpu_to_le16(offset);
5879 pSMB->SetupCount = 1;
5880 pSMB->Reserved3 = 0;
5881 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5882 byte_count = 3 /* pad */ + params + count;
5883
5884 pSMB->DataCount = cpu_to_le16(count);
5885 pSMB->ParameterCount = cpu_to_le16(params);
5886 pSMB->TotalDataCount = pSMB->DataCount;
5887 pSMB->TotalParameterCount = pSMB->ParameterCount;
5888 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5889 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5890 else
5891 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5892 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005893 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005894 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 pSMB->ByteCount = cpu_to_le16(byte_count);
5896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005898 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005899 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
5901 cifs_buf_release(pSMB);
5902
5903 if (rc == -EAGAIN)
5904 goto SetTimesRetry;
5905
Ronnie Sahlberg8e408fc2020-07-15 08:18:05 +10005906 if (rc == -EOPNOTSUPP)
5907 return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5908 nls_codepage, cifs_sb);
5909
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 return rc;
5911}
5912
Jeff Layton654cf142009-07-09 20:02:49 -04005913static void
5914cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5915 const struct cifs_unix_set_info_args *args)
5916{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005917 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005918 u64 mode = args->mode;
5919
Eric W. Biederman49418b22013-02-06 00:57:56 -08005920 if (uid_valid(args->uid))
5921 uid = from_kuid(&init_user_ns, args->uid);
5922 if (gid_valid(args->gid))
5923 gid = from_kgid(&init_user_ns, args->gid);
5924
Jeff Layton654cf142009-07-09 20:02:49 -04005925 /*
5926 * Samba server ignores set of file size to zero due to bugs in some
5927 * older clients, but we should be precise - we use SetFileSize to
5928 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005929 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005930 * zero instead of -1 here
5931 */
5932 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5933 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5934 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5935 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5936 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005937 data_offset->Uid = cpu_to_le64(uid);
5938 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005939 /* better to leave device as zero when it is */
5940 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5941 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5942 data_offset->Permissions = cpu_to_le64(mode);
5943
5944 if (S_ISREG(mode))
5945 data_offset->Type = cpu_to_le32(UNIX_FILE);
5946 else if (S_ISDIR(mode))
5947 data_offset->Type = cpu_to_le32(UNIX_DIR);
5948 else if (S_ISLNK(mode))
5949 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5950 else if (S_ISCHR(mode))
5951 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5952 else if (S_ISBLK(mode))
5953 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5954 else if (S_ISFIFO(mode))
5955 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5956 else if (S_ISSOCK(mode))
5957 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5958}
5959
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005961CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005962 const struct cifs_unix_set_info_args *args,
5963 u16 fid, u32 pid_of_opener)
5964{
5965 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005966 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005967 int rc = 0;
5968 u16 params, param_offset, offset, byte_count, count;
5969
Joe Perchesf96637b2013-05-04 22:12:25 -05005970 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005971 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5972
5973 if (rc)
5974 return rc;
5975
5976 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5977 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5978
5979 params = 6;
5980 pSMB->MaxSetupCount = 0;
5981 pSMB->Reserved = 0;
5982 pSMB->Flags = 0;
5983 pSMB->Timeout = 0;
5984 pSMB->Reserved2 = 0;
5985 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5986 offset = param_offset + params;
5987
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005988 data_offset = (char *)pSMB +
5989 offsetof(struct smb_hdr, Protocol) + offset;
5990
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005991 count = sizeof(FILE_UNIX_BASIC_INFO);
5992
5993 pSMB->MaxParameterCount = cpu_to_le16(2);
5994 /* BB find max SMB PDU from sess */
5995 pSMB->MaxDataCount = cpu_to_le16(1000);
5996 pSMB->SetupCount = 1;
5997 pSMB->Reserved3 = 0;
5998 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5999 byte_count = 3 /* pad */ + params + count;
6000 pSMB->DataCount = cpu_to_le16(count);
6001 pSMB->ParameterCount = cpu_to_le16(params);
6002 pSMB->TotalDataCount = pSMB->DataCount;
6003 pSMB->TotalParameterCount = pSMB->ParameterCount;
6004 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6005 pSMB->DataOffset = cpu_to_le16(offset);
6006 pSMB->Fid = fid;
6007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6008 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006009 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006010 pSMB->ByteCount = cpu_to_le16(byte_count);
6011
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006012 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006013
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006014 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006015 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006016 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006017 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6018 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006019
6020 /* Note: On -EAGAIN error only caller can retry on handle based calls
6021 since file handle passed in no longer valid */
6022
6023 return rc;
6024}
6025
6026int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006027CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006028 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006029 const struct cifs_unix_set_info_args *args,
6030 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031{
6032 TRANSACTION2_SPI_REQ *pSMB = NULL;
6033 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6034 int name_len;
6035 int rc = 0;
6036 int bytes_returned = 0;
6037 FILE_UNIX_BASIC_INFO *data_offset;
6038 __u16 params, param_offset, offset, count, byte_count;
6039
Joe Perchesf96637b2013-05-04 22:12:25 -05006040 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041setPermsRetry:
6042 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6043 (void **) &pSMBr);
6044 if (rc)
6045 return rc;
6046
6047 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6048 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006049 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006050 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 name_len++; /* trailing null */
6052 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006053 } else {
6054 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 }
6056
6057 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006058 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006060 /* BB find max SMB PDU from sess structure BB */
6061 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 pSMB->MaxSetupCount = 0;
6063 pSMB->Reserved = 0;
6064 pSMB->Flags = 0;
6065 pSMB->Timeout = 0;
6066 pSMB->Reserved2 = 0;
6067 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006068 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 offset = param_offset + params;
Steve Frenchb019e112021-07-01 21:01:19 -05006070 /* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
6071 data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 memset(data_offset, 0, count);
6073 pSMB->DataOffset = cpu_to_le16(offset);
6074 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6075 pSMB->SetupCount = 1;
6076 pSMB->Reserved3 = 0;
6077 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6078 byte_count = 3 /* pad */ + params + count;
6079 pSMB->ParameterCount = cpu_to_le16(params);
6080 pSMB->DataCount = cpu_to_le16(count);
6081 pSMB->TotalParameterCount = pSMB->ParameterCount;
6082 pSMB->TotalDataCount = pSMB->DataCount;
6083 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6084 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006085 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006086
Jeff Layton654cf142009-07-09 20:02:49 -04006087 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088
6089 pSMB->ByteCount = cpu_to_le16(byte_count);
6090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006092 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006093 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094
Steve French0d817bc2008-05-22 02:02:03 +00006095 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 if (rc == -EAGAIN)
6097 goto setPermsRetry;
6098 return rc;
6099}
6100
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006102/*
6103 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6104 * function used by listxattr and getxattr type calls. When ea_name is set,
6105 * it looks for that attribute name and stuffs that value into the EAData
6106 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6107 * buffer. In both cases, the return value is either the length of the
6108 * resulting data or a negative error code. If EAData is a NULL pointer then
6109 * the data isn't copied to it, but the length is returned.
6110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006112CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006113 const unsigned char *searchName, const unsigned char *ea_name,
6114 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006115 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116{
6117 /* BB assumes one setup word */
6118 TRANSACTION2_QPI_REQ *pSMB = NULL;
6119 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006120 int remap = cifs_remap(cifs_sb);
6121 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 int rc = 0;
6123 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006124 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006125 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006126 struct fea *temp_fea;
6127 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006128 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006129 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006130 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131
Joe Perchesf96637b2013-05-04 22:12:25 -05006132 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133QAllEAsRetry:
6134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6135 (void **) &pSMBr);
6136 if (rc)
6137 return rc;
6138
6139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006140 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006141 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6142 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 list_len++; /* trailing null */
6144 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006145 } else {
6146 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 }
6148
Jeff Layton6e462b92010-02-10 16:18:26 -05006149 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 pSMB->TotalDataCount = 0;
6151 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006152 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006153 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 pSMB->MaxSetupCount = 0;
6155 pSMB->Reserved = 0;
6156 pSMB->Flags = 0;
6157 pSMB->Timeout = 0;
6158 pSMB->Reserved2 = 0;
6159 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006160 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 pSMB->DataCount = 0;
6162 pSMB->DataOffset = 0;
6163 pSMB->SetupCount = 1;
6164 pSMB->Reserved3 = 0;
6165 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6166 byte_count = params + 1 /* pad */ ;
6167 pSMB->TotalParameterCount = cpu_to_le16(params);
6168 pSMB->ParameterCount = pSMB->TotalParameterCount;
6169 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6170 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006171 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 pSMB->ByteCount = cpu_to_le16(byte_count);
6173
6174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6175 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6176 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006177 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180
6181
6182 /* BB also check enough total bytes returned */
6183 /* BB we need to improve the validity checking
6184 of these trans2 responses */
6185
6186 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006187 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006188 rc = -EIO; /* bad smb */
6189 goto QAllEAsOut;
6190 }
6191
6192 /* check that length of list is not more than bcc */
6193 /* check that each entry does not go beyond length
6194 of list */
6195 /* check that each element of each entry does not
6196 go beyond end of list */
6197 /* validate_trans2_offsets() */
6198 /* BB check if start of smb + data_offset > &bcc+ bcc */
6199
6200 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6201 ea_response_data = (struct fealist *)
6202 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6203
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006205 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006206 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006207 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006208 /* didn't find the named attribute */
6209 if (ea_name)
6210 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 goto QAllEAsOut;
6212 }
6213
Jeff Layton0cd126b2010-02-10 16:18:26 -05006214 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006215 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006216 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006217 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006218 rc = -EIO;
6219 goto QAllEAsOut;
6220 }
6221
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006223 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006224 temp_fea = ea_response_data->list;
6225 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006226 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006227 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006228 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229
Jeff Layton6e462b92010-02-10 16:18:26 -05006230 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006231 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006232 /* make sure we can read name_len and value_len */
6233 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006234 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006235 rc = -EIO;
6236 goto QAllEAsOut;
6237 }
6238
6239 name_len = temp_fea->name_len;
6240 value_len = le16_to_cpu(temp_fea->value_len);
6241 list_len -= name_len + 1 + value_len;
6242 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006243 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006244 rc = -EIO;
6245 goto QAllEAsOut;
6246 }
6247
Jeff Layton31c05192010-02-10 16:18:26 -05006248 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006249 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006250 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006251 temp_ptr += name_len + 1;
6252 rc = value_len;
6253 if (buf_size == 0)
6254 goto QAllEAsOut;
6255 if ((size_t)value_len > buf_size) {
6256 rc = -ERANGE;
6257 goto QAllEAsOut;
6258 }
6259 memcpy(EAData, temp_ptr, value_len);
6260 goto QAllEAsOut;
6261 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006262 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006263 /* account for prefix user. and trailing null */
6264 rc += (5 + 1 + name_len);
6265 if (rc < (int) buf_size) {
6266 memcpy(EAData, "user.", 5);
6267 EAData += 5;
6268 memcpy(EAData, temp_ptr, name_len);
6269 EAData += name_len;
6270 /* null terminate name */
6271 *EAData = 0;
6272 ++EAData;
6273 } else if (buf_size == 0) {
6274 /* skip copy - calc size only */
6275 } else {
6276 /* stop before overrun buffer */
6277 rc = -ERANGE;
6278 break;
6279 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006281 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006282 temp_fea = (struct fea *)temp_ptr;
6283 }
6284
Jeff Layton31c05192010-02-10 16:18:26 -05006285 /* didn't find the named attribute */
6286 if (ea_name)
6287 rc = -ENODATA;
6288
Jeff Laytonf0d38682010-02-10 16:18:26 -05006289QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006290 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 if (rc == -EAGAIN)
6292 goto QAllEAsRetry;
6293
6294 return (ssize_t)rc;
6295}
6296
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006298CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6299 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006300 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006301 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302{
6303 struct smb_com_transaction2_spi_req *pSMB = NULL;
6304 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6305 struct fealist *parm_data;
6306 int name_len;
6307 int rc = 0;
6308 int bytes_returned = 0;
6309 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006310 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
Joe Perchesf96637b2013-05-04 22:12:25 -05006312 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313SetEARetry:
6314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6315 (void **) &pSMBr);
6316 if (rc)
6317 return rc;
6318
6319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6320 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006321 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6322 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 name_len++; /* trailing null */
6324 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006325 } else {
6326 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 }
6328
6329 params = 6 + name_len;
6330
6331 /* done calculating parms using name_len of file name,
6332 now use name_len to calculate length of ea name
6333 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006334 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 name_len = 0;
6336 else
Steve French50c2f752007-07-13 00:33:32 +00006337 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006339 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006341 /* BB find max SMB PDU from sess */
6342 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343 pSMB->MaxSetupCount = 0;
6344 pSMB->Reserved = 0;
6345 pSMB->Flags = 0;
6346 pSMB->Timeout = 0;
6347 pSMB->Reserved2 = 0;
6348 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006349 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 offset = param_offset + params;
6351 pSMB->InformationLevel =
6352 cpu_to_le16(SMB_SET_FILE_EA);
6353
Arnd Bergmannade7db92018-02-02 16:48:47 +01006354 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6356 pSMB->DataOffset = cpu_to_le16(offset);
6357 pSMB->SetupCount = 1;
6358 pSMB->Reserved3 = 0;
6359 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6360 byte_count = 3 /* pad */ + params + count;
6361 pSMB->DataCount = cpu_to_le16(count);
6362 parm_data->list_len = cpu_to_le32(count);
6363 parm_data->list[0].EA_flags = 0;
6364 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006365 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006367 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006368 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 parm_data->list[0].name[name_len] = 0;
6370 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6371 /* caller ensures that ea_value_len is less than 64K but
6372 we need to ensure that it fits within the smb */
6373
Steve French50c2f752007-07-13 00:33:32 +00006374 /*BB add length check to see if it would fit in
6375 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006376 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6377 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006378 memcpy(parm_data->list[0].name+name_len+1,
6379 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
6381 pSMB->TotalDataCount = pSMB->DataCount;
6382 pSMB->ParameterCount = cpu_to_le16(params);
6383 pSMB->TotalParameterCount = pSMB->ParameterCount;
6384 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006385 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 pSMB->ByteCount = cpu_to_le16(byte_count);
6387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006389 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006390 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
6392 cifs_buf_release(pSMB);
6393
6394 if (rc == -EAGAIN)
6395 goto SetEARetry;
6396
6397 return rc;
6398}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399#endif