blob: bf41ee048396d09b5484e41823d5980553d61179 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Pavel Shilovskyd9191312019-12-10 11:44:52 -080045#include "smb2proto.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040046#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070047#include "smbdirect.h"
Paulo Alcantara08744012018-11-14 17:24:29 -020048#ifdef CONFIG_CIFS_DFS_UPCALL
49#include "dfs_cache.h"
50#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#ifdef CONFIG_CIFS_POSIX
53static struct {
54 int index;
55 char *name;
56} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000057#ifdef CONFIG_CIFS_WEAK_PW_HASH
58 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000059 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000060#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000061 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000062 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 {BAD_PROT, "\2"}
64};
65#else
66static struct {
67 int index;
68 char *name;
69} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000070#ifdef CONFIG_CIFS_WEAK_PW_HASH
71 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000072 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000073#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000074 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 {BAD_PROT, "\2"}
76};
77#endif
78
Steve French39798772006-05-31 22:40:51 +000079/* define the number of elements in the cifs dialect array */
80#ifdef CONFIG_CIFS_POSIX
81#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000082#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000083#else
84#define CIFS_NUM_PROT 2
85#endif /* CIFS_WEAK_PW_HASH */
86#else /* not posix */
87#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000088#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000089#else
90#define CIFS_NUM_PROT 1
91#endif /* CONFIG_CIFS_WEAK_PW_HASH */
92#endif /* CIFS_POSIX */
93
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040094/*
95 * Mark as invalid, all open files on tree connections since they
96 * were closed when session to server was lost.
97 */
98void
99cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
101 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000102 struct list_head *tmp;
103 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400105 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500106 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400107 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000108 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000109 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400110 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 }
Steve French3afca262016-09-22 18:58:16 -0500112 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500113
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000114 mutex_lock(&tcon->crfid.fid_mutex);
115 tcon->crfid.is_valid = false;
Pavel Shilovskyd9191312019-12-10 11:44:52 -0800116 /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
117 close_shroot_lease_locked(&tcon->crfid);
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000118 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
119 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500120
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400121 /*
122 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
123 * to this tcon.
124 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Paulo Alcantara08744012018-11-14 17:24:29 -0200127#ifdef CONFIG_CIFS_DFS_UPCALL
128static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
129 struct cifs_tcon *tcon)
130{
131 int rc;
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300132 struct TCP_Server_Info *server = tcon->ses->server;
Paulo Alcantara08744012018-11-14 17:24:29 -0200133 struct dfs_cache_tgt_list tl;
134 struct dfs_cache_tgt_iterator *it = NULL;
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100135 char *tree;
Paulo Alcantara08744012018-11-14 17:24:29 -0200136 const char *tcp_host;
137 size_t tcp_host_len;
138 const char *dfs_host;
139 size_t dfs_host_len;
140
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100141 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
142 if (!tree)
143 return -ENOMEM;
144
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100145 if (!tcon->dfs_path) {
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300146 if (tcon->ipc) {
147 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
148 server->hostname);
149 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
150 } else {
151 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
152 }
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100153 goto out;
154 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200155
156 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
157 if (rc)
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100158 goto out;
Paulo Alcantara08744012018-11-14 17:24:29 -0200159
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300160 extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
Paulo Alcantara08744012018-11-14 17:24:29 -0200161
162 for (it = dfs_cache_get_tgt_iterator(&tl); it;
163 it = dfs_cache_get_next_tgt(&tl, it)) {
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300164 const char *share, *prefix;
165 size_t share_len, prefix_len;
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300166 bool target_match;
Paulo Alcantara08744012018-11-14 17:24:29 -0200167
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300168 rc = dfs_cache_get_tgt_share(it, &share, &share_len, &prefix,
169 &prefix_len);
170 if (rc) {
171 cifs_dbg(VFS, "%s: failed to parse target share %d\n",
172 __func__, rc);
173 continue;
174 }
175
176 extract_unc_hostname(share, &dfs_host, &dfs_host_len);
Paulo Alcantara08744012018-11-14 17:24:29 -0200177
178 if (dfs_host_len != tcp_host_len
179 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
Steve Frenchadbb2da2020-05-30 16:45:11 -0500180 cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n",
Paulo Alcantara08744012018-11-14 17:24:29 -0200181 __func__,
182 (int)dfs_host_len, dfs_host,
183 (int)tcp_host_len, tcp_host);
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300184
185 rc = match_target_ip(server, dfs_host, dfs_host_len,
186 &target_match);
187 if (rc) {
188 cifs_dbg(VFS, "%s: failed to match target ip: %d\n",
189 __func__, rc);
190 break;
191 }
192
193 if (!target_match) {
194 cifs_dbg(FYI, "%s: skipping target\n", __func__);
195 continue;
196 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200197 }
198
Paulo Alcantarae4af35f2020-05-19 15:38:28 -0300199 if (tcon->ipc) {
200 scnprintf(tree, MAX_TREE_SIZE, "\\\\%.*s\\IPC$",
201 (int)share_len, share);
202 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
203 } else {
204 scnprintf(tree, MAX_TREE_SIZE, "\\%.*s", (int)share_len,
205 share);
206 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
207 if (!rc) {
208 rc = update_super_prepath(tcon, prefix,
209 prefix_len);
210 break;
211 }
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300212 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200213 if (rc == -EREMOTE)
214 break;
215 }
216
217 if (!rc) {
218 if (it)
219 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
220 it);
221 else
222 rc = -ENOENT;
223 }
224 dfs_cache_free_tgts(&tl);
Aurelien Aptel15bc77f2019-01-08 13:41:00 +0100225out:
226 kfree(tree);
Paulo Alcantara08744012018-11-14 17:24:29 -0200227 return rc;
228}
229#else
230static inline int __cifs_reconnect_tcon(const struct nls_table *nlsc,
231 struct cifs_tcon *tcon)
232{
233 return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
234}
235#endif
236
Jeff Layton9162ab22009-09-03 12:07:17 -0400237/* reconnect the socket, tcon, and smb session if needed */
238static int
Steve French96daf2b2011-05-27 04:34:02 +0000239cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400240{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400241 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000242 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400243 struct TCP_Server_Info *server;
244 struct nls_table *nls_codepage;
Paulo Alcantara08744012018-11-14 17:24:29 -0200245 int retries;
Jeff Layton9162ab22009-09-03 12:07:17 -0400246
247 /*
248 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
249 * tcp and smb session status done differently for those three - in the
250 * calling routine
251 */
252 if (!tcon)
253 return 0;
254
255 ses = tcon->ses;
256 server = ses->server;
257
258 /*
259 * only tree disconnect, open, and write, (and ulogoff which does not
260 * have tcon) are allowed as we start force umount
261 */
262 if (tcon->tidStatus == CifsExiting) {
263 if (smb_command != SMB_COM_WRITE_ANDX &&
264 smb_command != SMB_COM_OPEN_ANDX &&
265 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500266 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
267 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400268 return -ENODEV;
269 }
270 }
271
Paulo Alcantara08744012018-11-14 17:24:29 -0200272 retries = server->nr_targets;
273
Jeff Layton9162ab22009-09-03 12:07:17 -0400274 /*
Paulo Alcantara08744012018-11-14 17:24:29 -0200275 * Give demultiplex thread up to 10 seconds to each target available for
276 * reconnect -- should be greater than cifs socket timeout which is 7
277 * seconds.
Jeff Layton9162ab22009-09-03 12:07:17 -0400278 */
279 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300280 rc = wait_event_interruptible_timeout(server->response_q,
281 (server->tcpStatus != CifsNeedReconnect),
282 10 * HZ);
283 if (rc < 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700284 cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
285 __func__);
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300286 return -ERESTARTSYS;
287 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400288
Steve Frenchfd88ce92011-04-12 01:01:14 +0000289 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400290 if (server->tcpStatus != CifsNeedReconnect)
291 break;
292
Ronnie Sahlberg09c40b12020-02-06 13:55:19 +1000293 if (retries && --retries)
Paulo Alcantara08744012018-11-14 17:24:29 -0200294 continue;
295
Jeff Layton9162ab22009-09-03 12:07:17 -0400296 /*
297 * on "soft" mounts we wait once. Hard mounts keep
298 * retrying until process is killed or server comes
299 * back on-line
300 */
Jeff Laytond4025392011-02-07 08:54:35 -0500301 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500302 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400303 return -EHOSTDOWN;
304 }
Paulo Alcantara08744012018-11-14 17:24:29 -0200305 retries = server->nr_targets;
Jeff Layton9162ab22009-09-03 12:07:17 -0400306 }
307
308 if (!ses->need_reconnect && !tcon->need_reconnect)
309 return 0;
310
311 nls_codepage = load_nls_default();
312
313 /*
314 * need to prevent multiple threads trying to simultaneously
315 * reconnect the same SMB session
316 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000317 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200318
319 /*
320 * Recheck after acquire mutex. If another thread is negotiating
321 * and the server never sends an answer the socket will be closed
322 * and tcpStatus set to reconnect.
323 */
324 if (server->tcpStatus == CifsNeedReconnect) {
325 rc = -EHOSTDOWN;
326 mutex_unlock(&ses->session_mutex);
327 goto out;
328 }
329
Jeff Layton198b5682010-04-24 07:57:48 -0400330 rc = cifs_negotiate_protocol(0, ses);
331 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400332 rc = cifs_setup_session(0, ses, nls_codepage);
333
334 /* do we need to reconnect tcon? */
335 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000336 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400337 goto out;
338 }
339
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400340 cifs_mark_open_files_invalid(tcon);
Paulo Alcantara08744012018-11-14 17:24:29 -0200341 rc = __cifs_reconnect_tcon(nls_codepage, tcon);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000342 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500343 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400344
Steve Frenchc318e6c2018-04-04 14:08:52 -0500345 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700346 pr_warn_once("reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400347 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500348 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400349
Jeff Layton9162ab22009-09-03 12:07:17 -0400350 atomic_inc(&tconInfoReconnectCount);
351
352 /* tell server Unix caps we support */
Stefan Metzmacher864138c2020-02-24 14:15:00 +0100353 if (cap_unix(ses))
Jeff Layton9162ab22009-09-03 12:07:17 -0400354 reset_cifs_unix_caps(0, tcon, NULL, NULL);
355
356 /*
357 * Removed call to reopen open files here. It is safer (and faster) to
358 * reopen files one at a time as needed in read and write.
359 *
360 * FIXME: what about file locks? don't we need to reclaim them ASAP?
361 */
362
363out:
364 /*
365 * Check if handle based operation so we know whether we can continue
366 * or not without returning to caller to reset file handle
367 */
368 switch (smb_command) {
369 case SMB_COM_READ_ANDX:
370 case SMB_COM_WRITE_ANDX:
371 case SMB_COM_CLOSE:
372 case SMB_COM_FIND_CLOSE2:
373 case SMB_COM_LOCKING_ANDX:
374 rc = -EAGAIN;
375 }
376
377 unload_nls(nls_codepage);
378 return rc;
379}
380
Steve Frenchad7a2922008-02-07 23:25:02 +0000381/* Allocate and return pointer to an SMB request buffer, and set basic
382 SMB information in the SMB header. If the return code is zero, this
383 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384static int
Steve French96daf2b2011-05-27 04:34:02 +0000385small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000386 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
Jeff Laytonf5695992010-09-29 15:27:08 -0400388 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Jeff Layton9162ab22009-09-03 12:07:17 -0400390 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000391 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 return rc;
393
394 *request_buf = cifs_small_buf_get();
395 if (*request_buf == NULL) {
396 /* BB should we add a retry in here if not a writepage? */
397 return -ENOMEM;
398 }
399
Steve French63135e02007-07-17 17:34:02 +0000400 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000401 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Steve French790fe572007-07-07 19:25:05 +0000403 if (tcon != NULL)
404 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700405
Jeff Laytonf5695992010-09-29 15:27:08 -0400406 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000407}
408
Steve French12b3b8f2006-02-09 21:12:47 +0000409int
Steve French50c2f752007-07-13 00:33:32 +0000410small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000411 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000412{
413 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000414 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000415
Steve French5815449d2006-02-14 01:36:20 +0000416 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000417 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000418 return rc;
419
Steve French04fdabe2006-02-10 05:52:50 +0000420 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400421 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000422 if (ses->capabilities & CAP_UNICODE)
423 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000424 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000425 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
426
427 /* uid, tid can stay at zero as set in header assemble */
428
Steve French50c2f752007-07-13 00:33:32 +0000429 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000430 this function is used after 1st of session setup requests */
431
432 return rc;
433}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435/* If the return code is zero, this function must fill in request_buf pointer */
436static int
Steve French96daf2b2011-05-27 04:34:02 +0000437__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400438 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 *request_buf = cifs_buf_get();
441 if (*request_buf == NULL) {
442 /* BB should we add a retry in here if not a writepage? */
443 return -ENOMEM;
444 }
445 /* Although the original thought was we needed the response buf for */
446 /* potential retries of smb operations it turns out we can determine */
447 /* from the mid flags when the request buffer can be resent without */
448 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000449 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000450 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
452 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000453 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Steve French790fe572007-07-07 19:25:05 +0000455 if (tcon != NULL)
456 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700457
Jeff Laytonf5695992010-09-29 15:27:08 -0400458 return 0;
459}
460
461/* If the return code is zero, this function must fill in request_buf pointer */
462static int
Steve French96daf2b2011-05-27 04:34:02 +0000463smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400464 void **request_buf, void **response_buf)
465{
466 int rc;
467
468 rc = cifs_reconnect_tcon(tcon, smb_command);
469 if (rc)
470 return rc;
471
472 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
473}
474
475static int
Steve French96daf2b2011-05-27 04:34:02 +0000476smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400477 void **request_buf, void **response_buf)
478{
479 if (tcon->ses->need_reconnect || tcon->need_reconnect)
480 return -EHOSTDOWN;
481
482 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Steve French50c2f752007-07-13 00:33:32 +0000485static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Jeff Layton12df83c2011-01-20 13:36:51 -0500487 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Jeff Layton12df83c2011-01-20 13:36:51 -0500489 /* check for plausible wct */
490 if (pSMB->hdr.WordCount < 10)
491 goto vt2_err;
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500494 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
495 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
496 goto vt2_err;
497
Jeff Layton12df83c2011-01-20 13:36:51 -0500498 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
499 if (total_size >= 512)
500 goto vt2_err;
501
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400502 /* check that bcc is at least as big as parms + data, and that it is
503 * less than negotiated smb buffer
504 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500505 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
506 if (total_size > get_bcc(&pSMB->hdr) ||
507 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
508 goto vt2_err;
509
510 return 0;
511vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000512 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500514 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515}
Jeff Layton690c5222011-01-20 13:36:51 -0500516
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400517static int
Jeff Layton3f618222013-06-12 19:52:14 -0500518decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400519{
520 int rc = 0;
521 u16 count;
522 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500523 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400524
525 count = get_bcc(&pSMBr->hdr);
526 if (count < SMB1_CLIENT_GUID_SIZE)
527 return -EIO;
528
529 spin_lock(&cifs_tcp_ses_lock);
530 if (server->srv_count > 1) {
531 spin_unlock(&cifs_tcp_ses_lock);
532 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
533 cifs_dbg(FYI, "server UID changed\n");
534 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
535 }
536 } else {
537 spin_unlock(&cifs_tcp_ses_lock);
538 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
539 }
540
541 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500542 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400543 } else {
544 count -= SMB1_CLIENT_GUID_SIZE;
545 rc = decode_negTokenInit(
546 pSMBr->u.extended_response.SecurityBlob, count, server);
547 if (rc != 1)
548 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400549 }
550
551 return 0;
552}
553
Jeff Layton9ddec562013-05-26 07:00:58 -0400554int
Jeff Layton38d77c52013-05-26 07:01:00 -0400555cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400556{
Jeff Layton502858822013-06-27 12:45:00 -0400557 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
558 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400559 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
560
561 /*
562 * Is signing required by mnt options? If not then check
563 * global_secflags to see if it is there.
564 */
565 if (!mnt_sign_required)
566 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
567 CIFSSEC_MUST_SIGN);
568
569 /*
570 * If signing is required then it's automatically enabled too,
571 * otherwise, check to see if the secflags allow it.
572 */
573 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
574 (global_secflags & CIFSSEC_MAY_SIGN);
575
576 /* If server requires signing, does client allow it? */
577 if (srv_sign_required) {
578 if (!mnt_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700579 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400580 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400581 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400582 server->sign = true;
583 }
584
585 /* If client requires signing, does server allow it? */
586 if (mnt_sign_required) {
587 if (!srv_sign_enabled) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700588 cifs_dbg(VFS, "Server does not support signing!\n");
Jeff Layton38d77c52013-05-26 07:01:00 -0400589 return -ENOTSUPP;
590 }
591 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400592 }
593
Long Libb4c0412018-04-17 12:17:08 -0700594 if (cifs_rdma_enabled(server) && server->sign)
Joe Perchesa0a30362020-04-14 22:42:53 -0700595 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
Long Libb4c0412018-04-17 12:17:08 -0700596
Jeff Layton9ddec562013-05-26 07:00:58 -0400597 return 0;
598}
599
Jeff Layton2190eca2013-05-26 07:00:57 -0400600#ifdef CONFIG_CIFS_WEAK_PW_HASH
601static int
Jeff Layton3f618222013-06-12 19:52:14 -0500602decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400603{
604 __s16 tmp;
605 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
606
607 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
608 return -EOPNOTSUPP;
609
Jeff Layton2190eca2013-05-26 07:00:57 -0400610 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
611 server->maxReq = min_t(unsigned int,
612 le16_to_cpu(rsp->MaxMpxCount),
613 cifs_max_pending);
614 set_credits(server, server->maxReq);
615 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800616 /* set up max_read for readpages check */
617 server->max_read = server->maxBuf;
Jeff Layton2190eca2013-05-26 07:00:57 -0400618 /* even though we do not use raw we might as well set this
619 accurately, in case we ever find a need for it */
620 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
621 server->max_rw = 0xFF00;
622 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
623 } else {
624 server->max_rw = 0;/* do not need to use raw anyway */
625 server->capabilities = CAP_MPX_MODE;
626 }
627 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
628 if (tmp == -1) {
629 /* OS/2 often does not set timezone therefore
630 * we must use server time to calc time zone.
631 * Could deviate slightly from the right zone.
632 * Smallest defined timezone difference is 15 minutes
633 * (i.e. Nepal). Rounding up/down is done to match
634 * this requirement.
635 */
636 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200637 struct timespec64 ts;
638 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400639 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
640 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200641 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
642 ts.tv_sec, utc,
643 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700644 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400645 seconds = abs(val);
646 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
647 remain = seconds % MIN_TZ_ADJ;
648 if (remain >= (MIN_TZ_ADJ / 2))
649 result += MIN_TZ_ADJ;
650 if (val < 0)
651 result = -result;
652 server->timeAdj = result;
653 } else {
654 server->timeAdj = (int)tmp;
655 server->timeAdj *= 60; /* also in seconds */
656 }
657 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
658
659
660 /* BB get server time for time conversions and add
661 code to use it and timezone since this is not UTC */
662
663 if (rsp->EncryptionKeyLength ==
664 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
665 memcpy(server->cryptkey, rsp->EncryptionKey,
666 CIFS_CRYPTO_KEY_SIZE);
667 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
668 return -EIO; /* need cryptkey unless plain text */
669 }
670
671 cifs_dbg(FYI, "LANMAN negotiated\n");
672 return 0;
673}
674#else
675static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500676decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400677{
678 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
679 return -EOPNOTSUPP;
680}
681#endif
682
Jeff Layton91934002013-05-26 07:00:58 -0400683static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500684should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400685{
Jeff Layton3f618222013-06-12 19:52:14 -0500686 switch (sectype) {
687 case RawNTLMSSP:
688 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400689 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500690 case Unspecified:
691 if (global_secflags &
692 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
693 return true;
694 /* Fallthrough */
695 default:
696 return false;
697 }
Jeff Layton91934002013-05-26 07:00:58 -0400698}
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400701CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 NEGOTIATE_REQ *pSMB;
704 NEGOTIATE_RSP *pSMBr;
705 int rc = 0;
706 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000707 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400708 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 u16 count;
710
Jeff Layton3534b852013-05-24 07:41:01 -0400711 if (!server) {
712 WARN(1, "%s: server is NULL!\n", __func__);
713 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
Jeff Layton3534b852013-05-24 07:41:01 -0400715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
717 (void **) &pSMB, (void **) &pSMBr);
718 if (rc)
719 return rc;
Steve French750d1152006-06-27 06:28:30 +0000720
Pavel Shilovsky88257362012-05-23 14:01:59 +0400721 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000722 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000723
Jeff Layton3f618222013-06-12 19:52:14 -0500724 if (should_set_ext_sec_flag(ses->sectype)) {
Joe Perchesa0a30362020-04-14 22:42:53 -0700725 cifs_dbg(FYI, "Requesting extended security\n");
Steve Frenchac683922009-05-06 04:16:04 +0000726 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
727 }
Steve French50c2f752007-07-13 00:33:32 +0000728
Steve French39798772006-05-31 22:40:51 +0000729 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000730 /*
731 * We know that all the name entries in the protocols array
732 * are short (< 16 bytes anyway) and are NUL terminated.
733 */
Steve French50c2f752007-07-13 00:33:32 +0000734 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000735 size_t len = strlen(protocols[i].name) + 1;
736
737 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
738 count += len;
Steve French39798772006-05-31 22:40:51 +0000739 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000740 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 pSMB->ByteCount = cpu_to_le16(count);
742
743 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000745 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000746 goto neg_err_exit;
747
Jeff Layton9bf67e52010-04-24 07:57:46 -0400748 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500749 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000750 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400751 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000752 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000753 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000754 could not negotiate a common dialect */
755 rc = -EOPNOTSUPP;
756 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000757 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400758 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500759 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400760 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000761 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000762 /* unknown wct */
763 rc = -EOPNOTSUPP;
764 goto neg_err_exit;
765 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400766 /* else wct == 17, NTLM or better */
767
Steve French96daf2b2011-05-27 04:34:02 +0000768 server->sec_mode = pSMBr->SecurityMode;
769 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500770 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000771
Steve French254e55e2006-06-04 05:53:15 +0000772 /* one byte, so no need to convert this or EncryptionKeyLen from
773 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300774 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
775 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400776 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000777 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400778 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Jones Syue1f641d92020-04-13 09:37:23 +0800779 /* set up max_read for readpages check */
780 server->max_read = server->maxBuf;
Steve Frencheca6acf2009-02-20 05:43:09 +0000781 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500782 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000783 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000784 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
785 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400786
Jeff Laytone598d1d82013-05-26 07:00:59 -0400787 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
788 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500789 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000790 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100791 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
792 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400793 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500794 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400795 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000796 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400797 } else {
798 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000799 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400800 }
Steve French254e55e2006-06-04 05:53:15 +0000801
802signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400803 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400804 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000805neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700806 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000807
Joe Perchesf96637b2013-05-04 22:12:25 -0500808 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return rc;
810}
811
812int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400813CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Joe Perchesf96637b2013-05-04 22:12:25 -0500818 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500819
820 /* BB: do we need to check this? These should never be NULL. */
821 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
822 return -EIO;
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500825 * No need to return error on this operation if tid invalidated and
826 * closed on server already e.g. due to tcp session crashing. Also,
827 * the tcon is no longer on the list, so no need to take lock before
828 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 */
Steve French268875b2009-06-25 00:29:21 +0000830 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000831 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Steve French50c2f752007-07-13 00:33:32 +0000833 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700834 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500835 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 return rc;
Steve French133672e2007-11-13 22:41:37 +0000837
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400838 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700839 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500841 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Steve French50c2f752007-07-13 00:33:32 +0000843 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500844 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (rc == -EAGAIN)
846 rc = 0;
847
848 return rc;
849}
850
Jeff Layton766fdbb2011-01-11 07:24:21 -0500851/*
852 * This is a no-op for now. We're not really interested in the reply, but
853 * rather in the fact that the server sent one and that server->lstrp
854 * gets updated.
855 *
856 * FIXME: maybe we should consider checking that the reply matches request?
857 */
858static void
859cifs_echo_callback(struct mid_q_entry *mid)
860{
861 struct TCP_Server_Info *server = mid->callback_data;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800862 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500863
864 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -0800865 add_credits(server, &credits, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500866}
867
868int
869CIFSSMBEcho(struct TCP_Server_Info *server)
870{
871 ECHO_REQ *smb;
872 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800873 struct kvec iov[2];
874 struct smb_rqst rqst = { .rq_iov = iov,
875 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500876
Joe Perchesf96637b2013-05-04 22:12:25 -0500877 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500878
879 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
880 if (rc)
881 return rc;
882
Steve French26c9cb62017-05-02 13:35:20 -0500883 if (server->capabilities & CAP_UNICODE)
884 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
885
Jeff Layton766fdbb2011-01-11 07:24:21 -0500886 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000887 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500888 smb->hdr.WordCount = 1;
889 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400890 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500891 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000892 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800893
894 iov[0].iov_len = 4;
895 iov[0].iov_base = smb;
896 iov[1].iov_len = get_rfc1002_length(smb);
897 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500898
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800899 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +1000900 server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500901 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500902 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500903
904 cifs_small_buf_release(smb);
905
906 return rc;
907}
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400910CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 LOGOFF_ANDX_REQ *pSMB;
913 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
Joe Perchesf96637b2013-05-04 22:12:25 -0500915 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500916
917 /*
918 * BB: do we need to check validity of ses and server? They should
919 * always be valid since we have an active reference. If not, that
920 * should probably be a BUG()
921 */
922 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 return -EIO;
924
Steve Frenchd7b619c2010-02-25 05:36:46 +0000925 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000926 if (ses->need_reconnect)
927 goto session_already_dead; /* no need to send SMBlogoff if uid
928 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
930 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000931 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return rc;
933 }
934
Pavel Shilovsky88257362012-05-23 14:01:59 +0400935 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700936
Jeff Layton38d77c52013-05-26 07:01:00 -0400937 if (ses->server->sign)
938 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 pSMB->hdr.Uid = ses->Suid;
941
942 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400943 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700944 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000945session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000946 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000949 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 error */
951 if (rc == -EAGAIN)
952 rc = 0;
953 return rc;
954}
955
956int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400957CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
958 const char *fileName, __u16 type,
959 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000960{
961 TRANSACTION2_SPI_REQ *pSMB = NULL;
962 TRANSACTION2_SPI_RSP *pSMBr = NULL;
963 struct unlink_psx_rq *pRqD;
964 int name_len;
965 int rc = 0;
966 int bytes_returned = 0;
967 __u16 params, param_offset, offset, byte_count;
968
Joe Perchesf96637b2013-05-04 22:12:25 -0500969 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000970PsxDelete:
971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
972 (void **) &pSMBr);
973 if (rc)
974 return rc;
975
976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
977 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600978 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
979 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000980 name_len++; /* trailing null */
981 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +1000982 } else {
983 name_len = copy_path_name(pSMB->FileName, fileName);
Steve French2d785a52007-07-15 01:48:57 +0000984 }
985
986 params = 6 + name_len;
987 pSMB->MaxParameterCount = cpu_to_le16(2);
988 pSMB->MaxDataCount = 0; /* BB double check this with jra */
989 pSMB->MaxSetupCount = 0;
990 pSMB->Reserved = 0;
991 pSMB->Flags = 0;
992 pSMB->Timeout = 0;
993 pSMB->Reserved2 = 0;
994 param_offset = offsetof(struct smb_com_transaction2_spi_req,
995 InformationLevel) - 4;
996 offset = param_offset + params;
997
998 /* Setup pointer to Request Data (inode type) */
999 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
1000 pRqD->type = cpu_to_le16(type);
1001 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1002 pSMB->DataOffset = cpu_to_le16(offset);
1003 pSMB->SetupCount = 1;
1004 pSMB->Reserved3 = 0;
1005 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1006 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
1007
1008 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
1009 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
1010 pSMB->ParameterCount = cpu_to_le16(params);
1011 pSMB->TotalParameterCount = pSMB->ParameterCount;
1012 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
1013 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001014 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +00001015 pSMB->ByteCount = cpu_to_le16(byte_count);
1016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00001018 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001019 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +00001020 cifs_buf_release(pSMB);
1021
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001022 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +00001023
1024 if (rc == -EAGAIN)
1025 goto PsxDelete;
1026
1027 return rc;
1028}
1029
1030int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001031CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1032 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
1034 DELETE_FILE_REQ *pSMB = NULL;
1035 DELETE_FILE_RSP *pSMBr = NULL;
1036 int rc = 0;
1037 int bytes_returned;
1038 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001039 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041DelFileRetry:
1042 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
1043 (void **) &pSMBr);
1044 if (rc)
1045 return rc;
1046
1047 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -07001048 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
1049 PATH_MAX, cifs_sb->local_nls,
1050 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 name_len++; /* trailing null */
1052 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001053 } else {
1054 name_len = copy_path_name(pSMB->fileName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
1056 pSMB->SearchAttributes =
1057 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
1058 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001059 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001063 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +00001064 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001065 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 cifs_buf_release(pSMB);
1068 if (rc == -EAGAIN)
1069 goto DelFileRetry;
1070
1071 return rc;
1072}
1073
1074int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001075CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1076 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077{
1078 DELETE_DIRECTORY_REQ *pSMB = NULL;
1079 DELETE_DIRECTORY_RSP *pSMBr = NULL;
1080 int rc = 0;
1081 int bytes_returned;
1082 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001083 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Joe Perchesf96637b2013-05-04 22:12:25 -05001085 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086RmDirRetry:
1087 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
1088 (void **) &pSMBr);
1089 if (rc)
1090 return rc;
1091
1092 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +04001093 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1094 PATH_MAX, cifs_sb->local_nls,
1095 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 name_len++; /* trailing null */
1097 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001098 } else {
1099 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
1101
1102 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001103 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001107 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001108 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001109 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 cifs_buf_release(pSMB);
1112 if (rc == -EAGAIN)
1113 goto RmDirRetry;
1114 return rc;
1115}
1116
1117int
Steve Frenchc3ca78e2019-09-25 00:32:13 -05001118CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
1119 struct cifs_tcon *tcon, const char *name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001120 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
1122 int rc = 0;
1123 CREATE_DIRECTORY_REQ *pSMB = NULL;
1124 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1125 int bytes_returned;
1126 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001127 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Joe Perchesf96637b2013-05-04 22:12:25 -05001129 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130MkDirRetry:
1131 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1132 (void **) &pSMBr);
1133 if (rc)
1134 return rc;
1135
1136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001137 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001138 PATH_MAX, cifs_sb->local_nls,
1139 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 name_len++; /* trailing null */
1141 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001142 } else {
1143 name_len = copy_path_name(pSMB->DirName, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
1145
1146 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001147 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001151 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001152 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001153 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 cifs_buf_release(pSMB);
1156 if (rc == -EAGAIN)
1157 goto MkDirRetry;
1158 return rc;
1159}
1160
Steve French2dd29d32007-04-23 22:07:35 +00001161int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001162CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1163 __u32 posix_flags, __u64 mode, __u16 *netfid,
1164 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1165 const char *name, const struct nls_table *nls_codepage,
1166 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001167{
1168 TRANSACTION2_SPI_REQ *pSMB = NULL;
1169 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1170 int name_len;
1171 int rc = 0;
1172 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001173 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001174 OPEN_PSX_REQ *pdata;
1175 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001176
Joe Perchesf96637b2013-05-04 22:12:25 -05001177 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001178PsxCreat:
1179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1180 (void **) &pSMBr);
1181 if (rc)
1182 return rc;
1183
1184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1185 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001186 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1187 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001188 name_len++; /* trailing null */
1189 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001190 } else {
1191 name_len = copy_path_name(pSMB->FileName, name);
Steve French2dd29d32007-04-23 22:07:35 +00001192 }
1193
1194 params = 6 + name_len;
1195 count = sizeof(OPEN_PSX_REQ);
1196 pSMB->MaxParameterCount = cpu_to_le16(2);
1197 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1198 pSMB->MaxSetupCount = 0;
1199 pSMB->Reserved = 0;
1200 pSMB->Flags = 0;
1201 pSMB->Timeout = 0;
1202 pSMB->Reserved2 = 0;
1203 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001204 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001205 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001206 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001207 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001208 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001209 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001210 pdata->OpenFlags = cpu_to_le32(*pOplock);
1211 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1212 pSMB->DataOffset = cpu_to_le16(offset);
1213 pSMB->SetupCount = 1;
1214 pSMB->Reserved3 = 0;
1215 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1216 byte_count = 3 /* pad */ + params + count;
1217
1218 pSMB->DataCount = cpu_to_le16(count);
1219 pSMB->ParameterCount = cpu_to_le16(params);
1220 pSMB->TotalDataCount = pSMB->DataCount;
1221 pSMB->TotalParameterCount = pSMB->ParameterCount;
1222 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1223 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001224 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001225 pSMB->ByteCount = cpu_to_le16(byte_count);
1226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1228 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001229 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001230 goto psx_create_err;
1231 }
1232
Joe Perchesf96637b2013-05-04 22:12:25 -05001233 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1235
Jeff Layton820a8032011-05-04 08:05:26 -04001236 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001237 rc = -EIO; /* bad smb */
1238 goto psx_create_err;
1239 }
1240
1241 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001242 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001243 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001244
Steve French2dd29d32007-04-23 22:07:35 +00001245 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001246 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001247 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1248 /* Let caller know file was created so we can set the mode. */
1249 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001250 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001251 *pOplock |= CIFS_CREATE_ACTION;
1252 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001253 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1254 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001255 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001256 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001257 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001258 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001259 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001260 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001261 goto psx_create_err;
1262 }
Steve French50c2f752007-07-13 00:33:32 +00001263 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001264 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001265 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001266 }
Steve French2dd29d32007-04-23 22:07:35 +00001267
1268psx_create_err:
1269 cifs_buf_release(pSMB);
1270
Steve French65bc98b2009-07-10 15:27:25 +00001271 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001272 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001273 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001274 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001275
1276 if (rc == -EAGAIN)
1277 goto PsxCreat;
1278
Steve French50c2f752007-07-13 00:33:32 +00001279 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001280}
1281
Steve Frencha9d02ad2005-08-24 23:06:05 -07001282static __u16 convert_disposition(int disposition)
1283{
1284 __u16 ofun = 0;
1285
1286 switch (disposition) {
1287 case FILE_SUPERSEDE:
1288 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1289 break;
1290 case FILE_OPEN:
1291 ofun = SMBOPEN_OAPPEND;
1292 break;
1293 case FILE_CREATE:
1294 ofun = SMBOPEN_OCREATE;
1295 break;
1296 case FILE_OPEN_IF:
1297 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1298 break;
1299 case FILE_OVERWRITE:
1300 ofun = SMBOPEN_OTRUNC;
1301 break;
1302 case FILE_OVERWRITE_IF:
1303 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1304 break;
1305 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001306 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001307 ofun = SMBOPEN_OAPPEND; /* regular open */
1308 }
1309 return ofun;
1310}
1311
Jeff Layton35fc37d2008-05-14 10:22:03 -07001312static int
1313access_flags_to_smbopen_mode(const int access_flags)
1314{
1315 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1316
1317 if (masked_flags == GENERIC_READ)
1318 return SMBOPEN_READ;
1319 else if (masked_flags == GENERIC_WRITE)
1320 return SMBOPEN_WRITE;
1321
1322 /* just go for read/write */
1323 return SMBOPEN_READWRITE;
1324}
1325
Steve Frencha9d02ad2005-08-24 23:06:05 -07001326int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001327SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001328 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001329 const int access_flags, const int create_options, __u16 *netfid,
1330 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001331 const struct nls_table *nls_codepage, int remap)
1332{
1333 int rc = -EACCES;
1334 OPENX_REQ *pSMB = NULL;
1335 OPENX_RSP *pSMBr = NULL;
1336 int bytes_returned;
1337 int name_len;
1338 __u16 count;
1339
1340OldOpenRetry:
1341 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1342 (void **) &pSMBr);
1343 if (rc)
1344 return rc;
1345
1346 pSMB->AndXCommand = 0xFF; /* none */
1347
1348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1349 count = 1; /* account for one byte pad to word boundary */
1350 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001351 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1352 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001353 name_len++; /* trailing null */
1354 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001355 } else {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001356 count = 0; /* no pad */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001357 name_len = copy_path_name(pSMB->fileName, fileName);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001358 }
1359 if (*pOplock & REQ_OPLOCK)
1360 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001361 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001362 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001363
Steve Frencha9d02ad2005-08-24 23:06:05 -07001364 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001365 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001366 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1367 /* set file as system file if special file such
1368 as fifo and server expecting SFU style and
1369 no Unix extensions */
1370
Steve French790fe572007-07-07 19:25:05 +00001371 if (create_options & CREATE_OPTION_SPECIAL)
1372 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001373 else /* BB FIXME BB */
1374 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001375
Jeff Layton67750fb2008-05-09 22:28:02 +00001376 if (create_options & CREATE_OPTION_READONLY)
1377 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001378
1379 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001380/* pSMB->CreateOptions = cpu_to_le32(create_options &
1381 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001382 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001383
1384 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001385 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001386 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001387 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001388
1389 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001391 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001392 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001393 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001394 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001395 } else {
1396 /* BB verify if wct == 15 */
1397
Steve French582d21e2008-05-13 04:54:12 +00001398/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001399
1400 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1401 /* Let caller know file was created so we can set the mode. */
1402 /* Do we care about the CreateAction in any other cases? */
1403 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001404/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001405 *pOplock |= CIFS_CREATE_ACTION; */
1406 /* BB FIXME END */
1407
Steve French790fe572007-07-07 19:25:05 +00001408 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001409 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1410 pfile_info->LastAccessTime = 0; /* BB fixme */
1411 pfile_info->LastWriteTime = 0; /* BB fixme */
1412 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001413 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001414 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001415 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001416 pfile_info->AllocationSize =
1417 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1418 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001419 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001420 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001421 }
1422 }
1423
1424 cifs_buf_release(pSMB);
1425 if (rc == -EAGAIN)
1426 goto OldOpenRetry;
1427 return rc;
1428}
1429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001431CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1432 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
Colin Ian King1afdea42019-07-23 16:09:19 +01001434 int rc;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001435 OPEN_REQ *req = NULL;
1436 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 int bytes_returned;
1438 int name_len;
1439 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001440 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1441 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001442 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001443 const struct nls_table *nls = cifs_sb->local_nls;
1444 int create_options = oparms->create_options;
1445 int desired_access = oparms->desired_access;
1446 int disposition = oparms->disposition;
1447 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001450 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1451 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (rc)
1453 return rc;
1454
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001455 /* no commands go after this */
1456 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001458 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1459 /* account for one byte pad to word boundary */
1460 count = 1;
1461 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1462 path, PATH_MAX, nls, remap);
1463 /* trailing null */
1464 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001466 req->NameLength = cpu_to_le16(name_len);
1467 } else {
1468 /* BB improve check for buffer overruns BB */
1469 /* no pad */
1470 count = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10001471 name_len = copy_path_name(req->fileName, path);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001472 req->NameLength = cpu_to_le16(name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001474
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001475 if (*oplock & REQ_OPLOCK)
1476 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1477 else if (*oplock & REQ_BATCHOPLOCK)
1478 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1479
1480 req->DesiredAccess = cpu_to_le32(desired_access);
1481 req->AllocationSize = 0;
1482
1483 /*
1484 * Set file as system file if special file such as fifo and server
1485 * expecting SFU style and no Unix extensions.
1486 */
1487 if (create_options & CREATE_OPTION_SPECIAL)
1488 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1489 else
1490 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1491
1492 /*
1493 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1494 * sensitive checks for other servers such as Samba.
1495 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001497 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Jeff Layton67750fb2008-05-09 22:28:02 +00001499 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001500 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001501
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001502 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1503 req->CreateDisposition = cpu_to_le32(disposition);
1504 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1505
Steve French09d1db52005-04-28 22:41:08 -07001506 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001507 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1508 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
1510 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001511 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001513 req->ByteCount = cpu_to_le16(count);
1514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1515 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001516 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001518 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001519 cifs_buf_release(req);
1520 if (rc == -EAGAIN)
1521 goto openRetry;
1522 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001524
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001525 /* 1 byte no need to le_to_cpu */
1526 *oplock = rsp->OplockLevel;
1527 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001528 oparms->fid->netfid = rsp->Fid;
Aurelien Aptel86f740f2020-02-21 11:19:06 +01001529 oparms->fid->access = desired_access;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001530
1531 /* Let caller know file was created so we can set the mode. */
1532 /* Do we care about the CreateAction in any other cases? */
1533 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1534 *oplock |= CIFS_CREATE_ACTION;
1535
1536 if (buf) {
1537 /* copy from CreationTime to Attributes */
1538 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1539 /* the file_info buf is endian converted by caller */
1540 buf->AllocationSize = rsp->AllocationSize;
1541 buf->EndOfFile = rsp->EndOfFile;
1542 buf->NumberOfLinks = cpu_to_le32(1);
1543 buf->DeletePending = 0;
1544 }
1545
1546 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 return rc;
1548}
1549
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001550/*
1551 * Discard any remaining data in the current SMB. To do this, we borrow the
1552 * current bigbuf.
1553 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001554int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001555cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001556{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001557 unsigned int rfclen = server->pdu_size;
1558 int remaining = rfclen + server->vals->header_preamble_size -
1559 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001560
1561 while (remaining > 0) {
1562 int length;
1563
1564 length = cifs_read_from_socket(server, server->bigbuf,
1565 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001566 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001567 if (length < 0)
1568 return length;
1569 server->total_read += length;
1570 remaining -= length;
1571 }
1572
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001573 return 0;
1574}
1575
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001576static int
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001577__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1578 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001579{
1580 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001581
Pavel Shilovsky350be252017-04-10 10:31:33 -07001582 length = cifs_discard_remaining_data(server);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001583 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001584 mid->resp_buf = server->smallbuf;
1585 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001586 return length;
1587}
1588
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001589static int
1590cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1591{
1592 struct cifs_readdata *rdata = mid->callback_data;
1593
1594 return __cifs_readv_discard(server, mid, rdata->result);
1595}
1596
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001597int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001598cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1599{
1600 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001601 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001603 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001604 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001605 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001606 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001607
Joe Perchesf96637b2013-05-04 22:12:25 -05001608 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1609 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001610
1611 /*
1612 * read the rest of READ_RSP header (sans Data array), or whatever we
1613 * can if there's not enough data. At this point, we've read down to
1614 * the Mid.
1615 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001616 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001617 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001618
Al Viroa6137302016-01-09 19:37:16 -05001619 length = cifs_read_from_socket(server,
1620 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621 if (length < 0)
1622 return length;
1623 server->total_read += length;
1624
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001625 if (server->ops->is_session_expired &&
1626 server->ops->is_session_expired(buf)) {
1627 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001628 return -1;
1629 }
1630
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001631 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -08001632 server->ops->is_status_pending(buf, server)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001633 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001634 return -1;
1635 }
1636
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001637 /* set up first two iov for signature check and to get credits */
1638 rdata->iov[0].iov_base = buf;
Pavel Shilovskybb1bccb2019-01-17 16:18:38 -08001639 rdata->iov[0].iov_len = server->vals->header_preamble_size;
1640 rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1641 rdata->iov[1].iov_len =
1642 server->total_read - server->vals->header_preamble_size;
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001643 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1644 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1645 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1646 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1647
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001648 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001649 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001650 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001651 cifs_dbg(FYI, "%s: server returned error %d\n",
1652 __func__, rdata->result);
Pavel Shilovsky8004c782019-01-17 15:29:26 -08001653 /* normal error on read response */
1654 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001655 }
1656
1657 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001658 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001659 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1660 __func__, server->total_read,
1661 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001662 rdata->result = -EIO;
1663 return cifs_readv_discard(server, mid);
1664 }
1665
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001666 data_offset = server->ops->read_data_offset(buf) +
1667 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001668 if (data_offset < server->total_read) {
1669 /*
1670 * win2k8 sometimes sends an offset of 0 when the read
1671 * is beyond the EOF. Treat it as if the data starts just after
1672 * the header.
1673 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001674 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1675 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001676 data_offset = server->total_read;
1677 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1678 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001679 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1680 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001681 rdata->result = -EIO;
1682 return cifs_readv_discard(server, mid);
1683 }
1684
Joe Perchesf96637b2013-05-04 22:12:25 -05001685 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1686 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001687
1688 len = data_offset - server->total_read;
1689 if (len > 0) {
1690 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001691 length = cifs_read_from_socket(server,
1692 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001693 if (length < 0)
1694 return length;
1695 server->total_read += length;
1696 }
1697
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001698 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001699#ifdef CONFIG_CIFS_SMB_DIRECT
1700 use_rdma_mr = rdata->mr;
1701#endif
1702 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1703 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001704 /* data_len is corrupt -- discard frame */
1705 rdata->result = -EIO;
1706 return cifs_readv_discard(server, mid);
1707 }
1708
Jeff Layton8321fec2012-09-19 06:22:32 -07001709 length = rdata->read_into_pages(server, rdata, data_len);
1710 if (length < 0)
1711 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001712
Jeff Layton8321fec2012-09-19 06:22:32 -07001713 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001714
Joe Perchesf96637b2013-05-04 22:12:25 -05001715 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1716 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001717
1718 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001719 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001720 return cifs_readv_discard(server, mid);
1721
1722 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001723 mid->resp_buf = server->smallbuf;
1724 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001725 return length;
1726}
1727
1728static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001729cifs_readv_callback(struct mid_q_entry *mid)
1730{
1731 struct cifs_readdata *rdata = mid->callback_data;
1732 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1733 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001734 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1735 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001736 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001737 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001738 .rq_npages = rdata->nr_pages,
1739 .rq_pagesz = rdata->pagesz,
1740 .rq_tailsz = rdata->tailsz };
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001741 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001742
Joe Perchesf96637b2013-05-04 22:12:25 -05001743 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1744 __func__, mid->mid, mid->mid_state, rdata->result,
1745 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001746
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001747 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001748 case MID_RESPONSE_RECEIVED:
1749 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001750 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001751 int rc = 0;
1752
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001753 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001754 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001755 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001756 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1757 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001758 }
1759 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001760 task_io_account_read(rdata->got_bytes);
1761 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001762 break;
1763 case MID_REQUEST_SUBMITTED:
1764 case MID_RETRY_NEEDED:
1765 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001766 if (server->sign && rdata->got_bytes)
1767 /* reset bytes number since we can not check a sign */
1768 rdata->got_bytes = 0;
1769 /* FIXME: should this be counted toward the initiating task? */
1770 task_io_account_read(rdata->got_bytes);
1771 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001772 break;
1773 default:
1774 rdata->result = -EIO;
1775 }
1776
Jeff Laytonda472fc2012-03-23 14:40:53 -04001777 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001778 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08001779 add_credits(server, &credits, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001780}
1781
1782/* cifs_async_readv - send an async write, and set up mid to handle result */
1783int
1784cifs_async_readv(struct cifs_readdata *rdata)
1785{
1786 int rc;
1787 READ_REQ *smb = NULL;
1788 int wct;
1789 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001790 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1791 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001792
Joe Perchesf96637b2013-05-04 22:12:25 -05001793 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1794 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001795
1796 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1797 wct = 12;
1798 else {
1799 wct = 10; /* old style read */
1800 if ((rdata->offset >> 32) > 0) {
1801 /* can not handle this big offset for old */
1802 return -EIO;
1803 }
1804 }
1805
1806 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1807 if (rc)
1808 return rc;
1809
1810 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1811 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1812
1813 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001814 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001815 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1816 if (wct == 12)
1817 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1818 smb->Remaining = 0;
1819 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1820 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1821 if (wct == 12)
1822 smb->ByteCount = 0;
1823 else {
1824 /* old style read */
1825 struct smb_com_readx_req *smbr =
1826 (struct smb_com_readx_req *)smb;
1827 smbr->ByteCount = 0;
1828 }
1829
1830 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001831 rdata->iov[0].iov_base = smb;
1832 rdata->iov[0].iov_len = 4;
1833 rdata->iov[1].iov_base = (char *)smb + 4;
1834 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001835
Jeff Layton6993f742012-05-16 07:13:17 -04001836 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001837 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08001838 cifs_readv_callback, NULL, rdata, 0, NULL);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001839
1840 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001841 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001842 else
1843 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001844
1845 cifs_small_buf_release(smb);
1846 return rc;
1847}
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001850CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1851 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852{
1853 int rc = -EACCES;
1854 READ_REQ *pSMB = NULL;
1855 READ_RSP *pSMBr = NULL;
1856 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001857 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001858 int resp_buf_type = 0;
1859 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001860 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001861 __u32 pid = io_parms->pid;
1862 __u16 netfid = io_parms->netfid;
1863 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001864 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001865 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Joe Perchesf96637b2013-05-04 22:12:25 -05001867 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001868 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001869 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001870 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001871 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001872 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001873 /* can not handle this big offset for old */
1874 return -EIO;
1875 }
1876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
1878 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001879 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (rc)
1881 return rc;
1882
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001883 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1884 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1885
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 /* tcon and ses pointer are checked in smb_init */
1887 if (tcon->ses->server == NULL)
1888 return -ECONNABORTED;
1889
Steve Frenchec637e32005-12-12 20:53:18 -08001890 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001892 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001893 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001894 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001895
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 pSMB->Remaining = 0;
1897 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1898 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001899 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001900 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1901 else {
1902 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001903 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001904 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001905 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001906 }
Steve Frenchec637e32005-12-12 20:53:18 -08001907
1908 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001909 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001910 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1911 CIFS_LOG_ERROR, &rsp_iov);
1912 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001913 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001914 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001916 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 } else {
1918 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1919 data_length = data_length << 16;
1920 data_length += le16_to_cpu(pSMBr->DataLength);
1921 *nbytes = data_length;
1922
1923 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001924 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001926 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001927 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 rc = -EIO;
1929 *nbytes = 0;
1930 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001931 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001932 le16_to_cpu(pSMBr->DataOffset);
1933/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001934 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001935 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001936 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001937 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001938 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Steve French790fe572007-07-07 19:25:05 +00001942 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001943 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001944 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001945 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001946 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001947 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001948 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001949 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001950 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001951 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001952
1953 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 since file handle passed in no longer valid */
1955 return rc;
1956}
1957
Steve Frenchec637e32005-12-12 20:53:18 -08001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001960CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001961 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962{
1963 int rc = -EACCES;
1964 WRITE_REQ *pSMB = NULL;
1965 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001966 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 __u32 bytes_sent;
1968 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001969 __u32 pid = io_parms->pid;
1970 __u16 netfid = io_parms->netfid;
1971 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001972 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001973 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Steve Frencha24e2d72010-04-03 17:20:21 +00001975 *nbytes = 0;
1976
Joe Perchesf96637b2013-05-04 22:12:25 -05001977 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001978 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001979 return -ECONNABORTED;
1980
Steve French790fe572007-07-07 19:25:05 +00001981 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001982 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001983 else {
Steve French1c955182005-08-30 20:58:07 -07001984 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001985 if ((offset >> 32) > 0) {
1986 /* can not handle big offset for old srv */
1987 return -EIO;
1988 }
1989 }
Steve French1c955182005-08-30 20:58:07 -07001990
1991 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 (void **) &pSMBr);
1993 if (rc)
1994 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001995
1996 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1997 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 /* tcon and ses pointer are checked in smb_init */
2000 if (tcon->ses->server == NULL)
2001 return -ECONNABORTED;
2002
2003 pSMB->AndXCommand = 0xFF; /* none */
2004 pSMB->Fid = netfid;
2005 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002006 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07002007 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 pSMB->Reserved = 0xFFFFFFFF;
2010 pSMB->WriteMode = 0;
2011 pSMB->Remaining = 0;
2012
Steve French50c2f752007-07-13 00:33:32 +00002013 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 can send more if LARGE_WRITE_X capability returned by the server and if
2015 our buffer is big enough or if we convert to iovecs on socket writes
2016 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00002017 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
2019 } else {
2020 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
2021 & ~0xFF;
2022 }
2023
2024 if (bytes_sent > count)
2025 bytes_sent = count;
2026 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002027 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00002028 if (buf)
Steve French61e74802008-12-03 00:57:54 +00002029 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04002030 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 /* No buffer */
2032 cifs_buf_release(pSMB);
2033 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07002034 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00002035 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07002036 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00002037 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07002038 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00002039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
2041 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002042 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07002043
Steve French790fe572007-07-07 19:25:05 +00002044 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07002045 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00002046 else { /* old style write has byte count 4 bytes earlier
2047 so 4 bytes pad */
2048 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07002049 (struct smb_com_writex_req *)pSMB;
2050 pSMBW->ByteCount = cpu_to_le16(byte_count);
2051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
2053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04002054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002055 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002057 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 } else {
2059 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2060 *nbytes = (*nbytes) << 16;
2061 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302062
2063 /*
2064 * Mask off high 16 bits when bytes written as returned by the
2065 * server is greater than bytes requested by the client. Some
2066 * OS/2 servers are known to set incorrect CountHigh values.
2067 */
2068 if (*nbytes > count)
2069 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 }
2071
2072 cifs_buf_release(pSMB);
2073
Steve French50c2f752007-07-13 00:33:32 +00002074 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 since file handle passed in no longer valid */
2076
2077 return rc;
2078}
2079
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080void
2081cifs_writedata_release(struct kref *refcount)
2082{
2083 struct cifs_writedata *wdata = container_of(refcount,
2084 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07002085#ifdef CONFIG_CIFS_SMB_DIRECT
2086 if (wdata->mr) {
2087 smbd_deregister_mr(wdata->mr);
2088 wdata->mr = NULL;
2089 }
2090#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091
2092 if (wdata->cfile)
2093 cifsFileInfo_put(wdata->cfile);
2094
Long Li8e7360f2018-05-30 12:47:56 -07002095 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002096 kfree(wdata);
2097}
2098
2099/*
2100 * Write failed with a retryable error. Resend the write request. It's also
2101 * possible that the page was redirtied so re-clean the page.
2102 */
2103static void
2104cifs_writev_requeue(struct cifs_writedata *wdata)
2105{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002106 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00002107 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07002108 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002109 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002110
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002111 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2112 i = 0;
2113 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002114 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002115 struct cifs_writedata *wdata2;
2116 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002117
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002118 wsize = server->ops->wp_retry_size(inode);
2119 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002120 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002121 if (!nr_pages) {
2122 rc = -ENOTSUPP;
2123 break;
2124 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002125 cur_len = nr_pages * PAGE_SIZE;
2126 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002127 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002128 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002129 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002130 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002131 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002132
2133 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2134 if (!wdata2) {
2135 rc = -ENOMEM;
2136 break;
2137 }
2138
2139 for (j = 0; j < nr_pages; j++) {
2140 wdata2->pages[j] = wdata->pages[i + j];
2141 lock_page(wdata2->pages[j]);
2142 clear_page_dirty_for_io(wdata2->pages[j]);
2143 }
2144
2145 wdata2->sync_mode = wdata->sync_mode;
2146 wdata2->nr_pages = nr_pages;
2147 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002148 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002149 wdata2->tailsz = tailsz;
2150 wdata2->bytes = cur_len;
2151
Aurelien Aptel86f740f2020-02-21 11:19:06 +01002152 rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002153 &wdata2->cfile);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002154 if (!wdata2->cfile) {
Pavel Shilovskyfe768d52019-01-29 12:15:11 -08002155 cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
2156 rc);
2157 if (!is_retryable_error(rc))
2158 rc = -EBADF;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002159 } else {
2160 wdata2->pid = wdata2->cfile->pid;
2161 rc = server->ops->async_writev(wdata2,
2162 cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002163 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002164
2165 for (j = 0; j < nr_pages; j++) {
2166 unlock_page(wdata2->pages[j]);
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002167 if (rc != 0 && !is_retryable_error(rc)) {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002168 SetPageError(wdata2->pages[j]);
2169 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002170 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002171 }
2172 }
2173
Adam McCoya4813792020-05-13 11:53:30 +00002174 kref_put(&wdata2->refcount, cifs_writedata_release);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002175 if (rc) {
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002176 if (is_retryable_error(rc))
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002177 continue;
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002178 i += nr_pages;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002179 break;
2180 }
2181
2182 rest_len -= cur_len;
2183 i += nr_pages;
2184 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002185
Pavel Shilovsky165df9a2019-01-29 16:40:28 -08002186 /* cleanup remaining pages from the original wdata */
2187 for (; i < wdata->nr_pages; i++) {
2188 SetPageError(wdata->pages[i]);
2189 end_page_writeback(wdata->pages[i]);
2190 put_page(wdata->pages[i]);
2191 }
2192
Pavel Shilovsky9a663962019-01-08 11:15:28 -08002193 if (rc != 0 && !is_retryable_error(rc))
2194 mapping_set_error(inode->i_mapping, rc);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002195 kref_put(&wdata->refcount, cifs_writedata_release);
2196}
2197
Jeff Laytonc2e87642012-03-23 14:40:55 -04002198void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002199cifs_writev_complete(struct work_struct *work)
2200{
2201 struct cifs_writedata *wdata = container_of(work,
2202 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002203 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002204 int i = 0;
2205
2206 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002207 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002208 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002209 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002210 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2211 wdata->bytes);
2212 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2213 return cifs_writev_requeue(wdata);
2214
2215 for (i = 0; i < wdata->nr_pages; i++) {
2216 struct page *page = wdata->pages[i];
2217 if (wdata->result == -EAGAIN)
2218 __set_page_dirty_nobuffers(page);
2219 else if (wdata->result < 0)
2220 SetPageError(page);
2221 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002222 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002223 }
2224 if (wdata->result != -EAGAIN)
2225 mapping_set_error(inode->i_mapping, wdata->result);
2226 kref_put(&wdata->refcount, cifs_writedata_release);
2227}
2228
2229struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002230cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002231{
Long Li8e7360f2018-05-30 12:47:56 -07002232 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002233 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002234 if (pages)
2235 return cifs_writedata_direct_alloc(pages, complete);
2236
2237 return NULL;
2238}
2239
2240struct cifs_writedata *
2241cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2242{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002243 struct cifs_writedata *wdata;
2244
Long Li8e7360f2018-05-30 12:47:56 -07002245 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002246 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002247 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002248 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002249 INIT_LIST_HEAD(&wdata->list);
2250 init_completion(&wdata->done);
2251 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002252 }
2253 return wdata;
2254}
2255
2256/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002257 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002258 * workqueue completion task.
2259 */
2260static void
2261cifs_writev_callback(struct mid_q_entry *mid)
2262{
2263 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002264 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002265 unsigned int written;
2266 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002267 struct cifs_credits credits = { .value = 1, .instance = 0 };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002268
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002269 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002270 case MID_RESPONSE_RECEIVED:
2271 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2272 if (wdata->result != 0)
2273 break;
2274
2275 written = le16_to_cpu(smb->CountHigh);
2276 written <<= 16;
2277 written += le16_to_cpu(smb->Count);
2278 /*
2279 * Mask off high 16 bits when bytes written as returned
2280 * by the server is greater than bytes requested by the
2281 * client. OS/2 servers are known to set incorrect
2282 * CountHigh values.
2283 */
2284 if (written > wdata->bytes)
2285 written &= 0xFFFF;
2286
2287 if (written < wdata->bytes)
2288 wdata->result = -ENOSPC;
2289 else
2290 wdata->bytes = written;
2291 break;
2292 case MID_REQUEST_SUBMITTED:
2293 case MID_RETRY_NEEDED:
2294 wdata->result = -EAGAIN;
2295 break;
2296 default:
2297 wdata->result = -EIO;
2298 break;
2299 }
2300
Jeff Laytonda472fc2012-03-23 14:40:53 -04002301 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002302 DeleteMidQEntry(mid);
Pavel Shilovsky34f4deb2019-01-16 11:22:29 -08002303 add_credits(tcon->ses->server, &credits, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002304}
2305
2306/* cifs_async_writev - send an async write, and set up mid to handle result */
2307int
Steve French4a5c80d2014-02-07 20:45:12 -06002308cifs_async_writev(struct cifs_writedata *wdata,
2309 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002310{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002311 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002312 WRITE_REQ *smb = NULL;
2313 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002314 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002315 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002316 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002317
2318 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2319 wct = 14;
2320 } else {
2321 wct = 12;
2322 if (wdata->offset >> 32 > 0) {
2323 /* can not handle big offset for old srv */
2324 return -EIO;
2325 }
2326 }
2327
2328 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2329 if (rc)
2330 goto async_writev_out;
2331
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002332 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2333 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002334
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002335 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002336 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002337 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2338 if (wct == 14)
2339 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2340 smb->Reserved = 0xFFFFFFFF;
2341 smb->WriteMode = 0;
2342 smb->Remaining = 0;
2343
2344 smb->DataOffset =
2345 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2346
2347 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002348 iov[0].iov_len = 4;
2349 iov[0].iov_base = smb;
2350 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2351 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002352
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002353 rqst.rq_iov = iov;
2354 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002355 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002356 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002357 rqst.rq_npages = wdata->nr_pages;
2358 rqst.rq_pagesz = wdata->pagesz;
2359 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002360
Joe Perchesf96637b2013-05-04 22:12:25 -05002361 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2362 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002363
2364 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2365 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2366
2367 if (wct == 14) {
2368 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2369 put_bcc(wdata->bytes + 1, &smb->hdr);
2370 } else {
2371 /* wct == 12 */
2372 struct smb_com_writex_req *smbw =
2373 (struct smb_com_writex_req *)smb;
2374 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2375 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002376 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002377 }
2378
2379 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002380 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky3349c3a2019-01-15 15:52:29 -08002381 cifs_writev_callback, NULL, wdata, 0, NULL);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002382
2383 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002384 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002385 else
Steve French4a5c80d2014-02-07 20:45:12 -06002386 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002387
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002388async_writev_out:
2389 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002390 return rc;
2391}
2392
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002393int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002394CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002395 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396{
Colin Ian King136a5dc2020-05-27 13:50:31 +01002397 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002399 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002400 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002401 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002402 __u32 pid = io_parms->pid;
2403 __u16 netfid = io_parms->netfid;
2404 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002405 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002406 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002407 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002409 *nbytes = 0;
2410
Joe Perchesf96637b2013-05-04 22:12:25 -05002411 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002412
Steve French4c3130e2008-12-09 00:28:16 +00002413 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002414 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002415 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002416 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002417 if ((offset >> 32) > 0) {
2418 /* can not handle big offset for old srv */
2419 return -EIO;
2420 }
2421 }
Steve French8cc64c62005-10-03 13:49:43 -07002422 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 if (rc)
2424 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002425
2426 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2427 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2428
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 /* tcon and ses pointer are checked in smb_init */
2430 if (tcon->ses->server == NULL)
2431 return -ECONNABORTED;
2432
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002433 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 pSMB->Fid = netfid;
2435 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002436 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002437 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 pSMB->Reserved = 0xFFFFFFFF;
2439 pSMB->WriteMode = 0;
2440 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002443 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
Steve French3e844692005-10-03 13:37:24 -07002445 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2446 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002447 /* header + 1 byte pad */
2448 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002449 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002450 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002451 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002452 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002453 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002454 pSMB->ByteCount = cpu_to_le16(count + 1);
2455 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002456 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002457 (struct smb_com_writex_req *)pSMB;
2458 pSMBW->ByteCount = cpu_to_le16(count + 5);
2459 }
Steve French3e844692005-10-03 13:37:24 -07002460 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002461 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002462 iov[0].iov_len = smb_hdr_len + 4;
2463 else /* wct == 12 pad bigger by four bytes */
2464 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002465
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002466 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2467 &rsp_iov);
2468 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002469 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002471 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002472 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002473 /* presumably this can not happen, but best to be safe */
2474 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002475 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002476 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002477 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2478 *nbytes = (*nbytes) << 16;
2479 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302480
2481 /*
2482 * Mask off high 16 bits when bytes written as returned by the
2483 * server is greater than bytes requested by the client. OS/2
2484 * servers are known to set incorrect CountHigh values.
2485 */
2486 if (*nbytes > count)
2487 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002490 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
Steve French50c2f752007-07-13 00:33:32 +00002492 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 since file handle passed in no longer valid */
2494
2495 return rc;
2496}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002497
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002498int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2499 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002500 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2501{
2502 int rc = 0;
2503 LOCK_REQ *pSMB = NULL;
2504 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002505 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002506 int resp_buf_type;
2507 __u16 count;
2508
Joe Perchesf96637b2013-05-04 22:12:25 -05002509 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2510 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002511
2512 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2513 if (rc)
2514 return rc;
2515
2516 pSMB->Timeout = 0;
2517 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2518 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2519 pSMB->LockType = lock_type;
2520 pSMB->AndXCommand = 0xFF; /* none */
2521 pSMB->Fid = netfid; /* netfid stays le */
2522
2523 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2524 inc_rfc1001_len(pSMB, count);
2525 pSMB->ByteCount = cpu_to_le16(count);
2526
2527 iov[0].iov_base = (char *)pSMB;
2528 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2529 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2530 iov[1].iov_base = (char *)buf;
2531 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2532
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002533 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002534 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2535 CIFS_NO_RSP_BUF, &rsp_iov);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002536 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002537 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002538 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002539
2540 return rc;
2541}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002542
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002544CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002545 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002547 const __u32 numLock, const __u8 lockType,
2548 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549{
2550 int rc = 0;
2551 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002552/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002554 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 __u16 count;
2556
Joe Perchesf96637b2013-05-04 22:12:25 -05002557 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2558 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002559 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 if (rc)
2562 return rc;
2563
Steve French790fe572007-07-07 19:25:05 +00002564 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002565 /* no response expected */
Ronnie Sahlberg392e1c52019-05-06 10:00:02 +10002566 flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002568 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002569 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2571 } else {
2572 pSMB->Timeout = 0;
2573 }
2574
2575 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2576 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2577 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002578 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 pSMB->AndXCommand = 0xFF; /* none */
2580 pSMB->Fid = smb_file_id; /* netfid stays le */
2581
Steve French790fe572007-07-07 19:25:05 +00002582 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002583 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 /* BB where to store pid high? */
2585 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2586 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2587 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2588 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2589 count = sizeof(LOCKING_ANDX_RANGE);
2590 } else {
2591 /* oplock break */
2592 count = 0;
2593 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002594 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 pSMB->ByteCount = cpu_to_le16(count);
2596
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002597 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002598 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002599 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002600 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002601 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002602 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002603 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002604 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002605 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Steve French50c2f752007-07-13 00:33:32 +00002607 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 since file handle passed in no longer valid */
2609 return rc;
2610}
2611
2612int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002613CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002614 const __u16 smb_file_id, const __u32 netpid,
2615 const loff_t start_offset, const __u64 len,
2616 struct file_lock *pLockData, const __u16 lock_type,
2617 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002618{
2619 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2620 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002621 struct cifs_posix_lock *parm_data;
2622 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002623 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002624 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002625 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002626 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002627 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002628 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002629
Joe Perchesf96637b2013-05-04 22:12:25 -05002630 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002631
Steve French08547b02006-02-28 22:39:25 +00002632 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2633
2634 if (rc)
2635 return rc;
2636
2637 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2638
Steve French50c2f752007-07-13 00:33:32 +00002639 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002640 pSMB->MaxSetupCount = 0;
2641 pSMB->Reserved = 0;
2642 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002643 pSMB->Reserved2 = 0;
2644 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2645 offset = param_offset + params;
2646
Steve French08547b02006-02-28 22:39:25 +00002647 count = sizeof(struct cifs_posix_lock);
2648 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002649 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002650 pSMB->SetupCount = 1;
2651 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002652 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002653 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2654 else
2655 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2656 byte_count = 3 /* pad */ + params + count;
2657 pSMB->DataCount = cpu_to_le16(count);
2658 pSMB->ParameterCount = cpu_to_le16(params);
2659 pSMB->TotalDataCount = pSMB->DataCount;
2660 pSMB->TotalParameterCount = pSMB->ParameterCount;
2661 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002662 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002663 (((char *) &pSMB->hdr.Protocol) + offset);
2664
2665 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002666 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002667 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002668 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002669 pSMB->Timeout = cpu_to_le32(-1);
2670 } else
2671 pSMB->Timeout = 0;
2672
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002673 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002674 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002675 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002676
2677 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002678 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002679 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2680 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002681 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002682 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002683 if (waitFlag) {
2684 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2685 (struct smb_hdr *) pSMBr, &bytes_returned);
2686 } else {
Steve French133672e2007-11-13 22:41:37 +00002687 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002688 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002689 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002690 &resp_buf_type, timeout, &rsp_iov);
2691 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002692 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002693 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002694
Steve French08547b02006-02-28 22:39:25 +00002695 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002696 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002697 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002698 /* lock structure can be returned on get */
2699 __u16 data_offset;
2700 __u16 data_count;
2701 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002702
Jeff Layton820a8032011-05-04 08:05:26 -04002703 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002704 rc = -EIO; /* bad smb */
2705 goto plk_err_exit;
2706 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002707 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2708 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002709 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002710 rc = -EIO;
2711 goto plk_err_exit;
2712 }
2713 parm_data = (struct cifs_posix_lock *)
2714 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002715 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002716 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002717 else {
2718 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002719 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002720 pLockData->fl_type = F_RDLCK;
2721 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002722 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002723 pLockData->fl_type = F_WRLCK;
2724
Steve French5443d132011-03-13 05:08:25 +00002725 pLockData->fl_start = le64_to_cpu(parm_data->start);
2726 pLockData->fl_end = pLockData->fl_start +
2727 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002728 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002729 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002730 }
Steve French50c2f752007-07-13 00:33:32 +00002731
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002732plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002733 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002734
Steve French08547b02006-02-28 22:39:25 +00002735 /* Note: On -EAGAIN error only caller can retry on handle based calls
2736 since file handle passed in no longer valid */
2737
2738 return rc;
2739}
2740
2741
2742int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002743CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
2745 int rc = 0;
2746 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002747 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
2749/* do not retry on dead session on close */
2750 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002751 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 return 0;
2753 if (rc)
2754 return rc;
2755
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002757 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002759 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002760 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002761 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002763 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002765 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 }
2767 }
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002770 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 rc = 0;
2772
2773 return rc;
2774}
2775
2776int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002777CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002778{
2779 int rc = 0;
2780 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002781 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002782
2783 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2784 if (rc)
2785 return rc;
2786
2787 pSMB->FileID = (__u16) smb_file_id;
2788 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002789 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002790 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002791 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002792 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002793 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002794
2795 return rc;
2796}
2797
2798int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002799CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002800 const char *from_name, const char *to_name,
2801 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 int rc = 0;
2804 RENAME_REQ *pSMB = NULL;
2805 RENAME_RSP *pSMBr = NULL;
2806 int bytes_returned;
2807 int name_len, name_len2;
2808 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002809 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810
Joe Perchesf96637b2013-05-04 22:12:25 -05002811 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812renameRetry:
2813 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2814 (void **) &pSMBr);
2815 if (rc)
2816 return rc;
2817
2818 pSMB->BufferFormat = 0x04;
2819 pSMB->SearchAttributes =
2820 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2821 ATTR_DIRECTORY);
2822
2823 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002824 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2825 from_name, PATH_MAX,
2826 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 name_len++; /* trailing null */
2828 name_len *= 2;
2829 pSMB->OldFileName[name_len] = 0x04; /* pad */
2830 /* protocol requires ASCII signature byte on Unicode string */
2831 pSMB->OldFileName[name_len + 1] = 0x00;
2832 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002833 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002834 to_name, PATH_MAX, cifs_sb->local_nls,
2835 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2837 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002838 } else {
2839 name_len = copy_path_name(pSMB->OldFileName, from_name);
2840 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 name_len2++; /* signature byte */
2843 }
2844
2845 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002846 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 pSMB->ByteCount = cpu_to_le16(count);
2848
2849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2850 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002851 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002852 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002853 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 cifs_buf_release(pSMB);
2856
2857 if (rc == -EAGAIN)
2858 goto renameRetry;
2859
2860 return rc;
2861}
2862
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002863int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002864 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002865 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866{
2867 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2868 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002869 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 char *data_offset;
2871 char dummy_string[30];
2872 int rc = 0;
2873 int bytes_returned = 0;
2874 int len_of_str;
2875 __u16 params, param_offset, offset, count, byte_count;
2876
Joe Perchesf96637b2013-05-04 22:12:25 -05002877 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2879 (void **) &pSMBr);
2880 if (rc)
2881 return rc;
2882
2883 params = 6;
2884 pSMB->MaxSetupCount = 0;
2885 pSMB->Reserved = 0;
2886 pSMB->Flags = 0;
2887 pSMB->Timeout = 0;
2888 pSMB->Reserved2 = 0;
2889 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2890 offset = param_offset + params;
2891
2892 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2893 rename_info = (struct set_file_rename *) data_offset;
2894 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002895 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 pSMB->SetupCount = 1;
2897 pSMB->Reserved3 = 0;
2898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2899 byte_count = 3 /* pad */ + params;
2900 pSMB->ParameterCount = cpu_to_le16(params);
2901 pSMB->TotalParameterCount = pSMB->ParameterCount;
2902 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2903 pSMB->DataOffset = cpu_to_le16(offset);
2904 /* construct random name ".cifs_tmp<inodenum><mid>" */
2905 rename_info->overwrite = cpu_to_le32(1);
2906 rename_info->root_fid = 0;
2907 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002908 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002909 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002910 len_of_str =
2911 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002912 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002914 len_of_str =
2915 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002916 target_name, PATH_MAX, nls_codepage,
2917 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 }
2919 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002920 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 byte_count += count;
2922 pSMB->DataCount = cpu_to_le16(count);
2923 pSMB->TotalDataCount = pSMB->DataCount;
2924 pSMB->Fid = netfid;
2925 pSMB->InformationLevel =
2926 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2927 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002928 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 pSMB->ByteCount = cpu_to_le16(byte_count);
2930 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002932 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002933 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002934 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2935 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002936
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 cifs_buf_release(pSMB);
2938
2939 /* Note: On -EAGAIN error only caller can retry on handle based calls
2940 since file handle passed in no longer valid */
2941
2942 return rc;
2943}
2944
2945int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002946CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2947 const char *fromName, const __u16 target_tid, const char *toName,
2948 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949{
2950 int rc = 0;
2951 COPY_REQ *pSMB = NULL;
2952 COPY_RSP *pSMBr = NULL;
2953 int bytes_returned;
2954 int name_len, name_len2;
2955 __u16 count;
2956
Joe Perchesf96637b2013-05-04 22:12:25 -05002957 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958copyRetry:
2959 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2960 (void **) &pSMBr);
2961 if (rc)
2962 return rc;
2963
2964 pSMB->BufferFormat = 0x04;
2965 pSMB->Tid2 = target_tid;
2966
2967 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2968
2969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002970 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2971 fromName, PATH_MAX, nls_codepage,
2972 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 name_len++; /* trailing null */
2974 name_len *= 2;
2975 pSMB->OldFileName[name_len] = 0x04; /* pad */
2976 /* protocol requires ASCII signature byte on Unicode string */
2977 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002978 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002979 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2980 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2982 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002983 } else {
2984 name_len = copy_path_name(pSMB->OldFileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002986 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len2++; /* signature byte */
2988 }
2989
2990 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002991 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 pSMB->ByteCount = cpu_to_le16(count);
2993
2994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2996 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002997 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2998 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
Steve French0d817bc2008-05-22 02:02:03 +00003000 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002 if (rc == -EAGAIN)
3003 goto copyRetry;
3004
3005 return rc;
3006}
3007
3008int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003009CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003011 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012{
3013 TRANSACTION2_SPI_REQ *pSMB = NULL;
3014 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3015 char *data_offset;
3016 int name_len;
3017 int name_len_target;
3018 int rc = 0;
3019 int bytes_returned = 0;
3020 __u16 params, param_offset, offset, byte_count;
3021
Joe Perchesf96637b2013-05-04 22:12:25 -05003022 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023createSymLinkRetry:
3024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3025 (void **) &pSMBr);
3026 if (rc)
3027 return rc;
3028
3029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3030 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003031 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
3032 /* find define for this maxpathcomponent */
3033 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 name_len++; /* trailing null */
3035 name_len *= 2;
3036
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003037 } else {
3038 name_len = copy_path_name(pSMB->FileName, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 }
3040 params = 6 + name_len;
3041 pSMB->MaxSetupCount = 0;
3042 pSMB->Reserved = 0;
3043 pSMB->Flags = 0;
3044 pSMB->Timeout = 0;
3045 pSMB->Reserved2 = 0;
3046 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003047 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 offset = param_offset + params;
3049
3050 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3052 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003053 cifsConvertToUTF16((__le16 *) data_offset, toName,
3054 /* find define for this maxpathcomponent */
3055 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 name_len_target++; /* trailing null */
3057 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003058 } else {
3059 name_len_target = copy_path_name(data_offset, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 }
3061
3062 pSMB->MaxParameterCount = cpu_to_le16(2);
3063 /* BB find exact max on data count below from sess */
3064 pSMB->MaxDataCount = cpu_to_le16(1000);
3065 pSMB->SetupCount = 1;
3066 pSMB->Reserved3 = 0;
3067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3068 byte_count = 3 /* pad */ + params + name_len_target;
3069 pSMB->DataCount = cpu_to_le16(name_len_target);
3070 pSMB->ParameterCount = cpu_to_le16(params);
3071 pSMB->TotalDataCount = pSMB->DataCount;
3072 pSMB->TotalParameterCount = pSMB->ParameterCount;
3073 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3074 pSMB->DataOffset = cpu_to_le16(offset);
3075 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
3076 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003077 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 pSMB->ByteCount = cpu_to_le16(byte_count);
3079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003081 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003082 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003083 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
3084 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
Steve French0d817bc2008-05-22 02:02:03 +00003086 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
3088 if (rc == -EAGAIN)
3089 goto createSymLinkRetry;
3090
3091 return rc;
3092}
3093
3094int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003095CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07003097 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098{
3099 TRANSACTION2_SPI_REQ *pSMB = NULL;
3100 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3101 char *data_offset;
3102 int name_len;
3103 int name_len_target;
3104 int rc = 0;
3105 int bytes_returned = 0;
3106 __u16 params, param_offset, offset, byte_count;
3107
Joe Perchesf96637b2013-05-04 22:12:25 -05003108 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109createHardLinkRetry:
3110 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3111 (void **) &pSMBr);
3112 if (rc)
3113 return rc;
3114
3115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06003116 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3117 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 name_len++; /* trailing null */
3119 name_len *= 2;
3120
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003121 } else {
3122 name_len = copy_path_name(pSMB->FileName, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 }
3124 params = 6 + name_len;
3125 pSMB->MaxSetupCount = 0;
3126 pSMB->Reserved = 0;
3127 pSMB->Flags = 0;
3128 pSMB->Timeout = 0;
3129 pSMB->Reserved2 = 0;
3130 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003131 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 offset = param_offset + params;
3133
3134 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3136 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003137 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3138 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 name_len_target++; /* trailing null */
3140 name_len_target *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003141 } else {
3142 name_len_target = copy_path_name(data_offset, fromName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 }
3144
3145 pSMB->MaxParameterCount = cpu_to_le16(2);
3146 /* BB find exact max on data count below from sess*/
3147 pSMB->MaxDataCount = cpu_to_le16(1000);
3148 pSMB->SetupCount = 1;
3149 pSMB->Reserved3 = 0;
3150 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3151 byte_count = 3 /* pad */ + params + name_len_target;
3152 pSMB->ParameterCount = cpu_to_le16(params);
3153 pSMB->TotalParameterCount = pSMB->ParameterCount;
3154 pSMB->DataCount = cpu_to_le16(name_len_target);
3155 pSMB->TotalDataCount = pSMB->DataCount;
3156 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3157 pSMB->DataOffset = cpu_to_le16(offset);
3158 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3159 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003160 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 pSMB->ByteCount = cpu_to_le16(byte_count);
3162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003164 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003165 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003166 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3167 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169 cifs_buf_release(pSMB);
3170 if (rc == -EAGAIN)
3171 goto createHardLinkRetry;
3172
3173 return rc;
3174}
3175
3176int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003177CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003178 const char *from_name, const char *to_name,
3179 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180{
3181 int rc = 0;
3182 NT_RENAME_REQ *pSMB = NULL;
3183 RENAME_RSP *pSMBr = NULL;
3184 int bytes_returned;
3185 int name_len, name_len2;
3186 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003187 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Joe Perchesf96637b2013-05-04 22:12:25 -05003189 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190winCreateHardLinkRetry:
3191
3192 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3193 (void **) &pSMBr);
3194 if (rc)
3195 return rc;
3196
3197 pSMB->SearchAttributes =
3198 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3199 ATTR_DIRECTORY);
3200 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3201 pSMB->ClusterCount = 0;
3202
3203 pSMB->BufferFormat = 0x04;
3204
3205 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3206 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003207 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3208 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 name_len++; /* trailing null */
3210 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003211
3212 /* protocol specifies ASCII buffer format (0x04) for unicode */
3213 pSMB->OldFileName[name_len] = 0x04;
3214 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003216 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003217 to_name, PATH_MAX, cifs_sb->local_nls,
3218 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3220 name_len2 *= 2; /* convert to bytes */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003221 } else {
3222 name_len = copy_path_name(pSMB->OldFileName, from_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003224 name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 name_len2++; /* signature byte */
3226 }
3227
3228 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003229 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 pSMB->ByteCount = cpu_to_le16(count);
3231
3232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003234 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003235 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003236 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 cifs_buf_release(pSMB);
3239 if (rc == -EAGAIN)
3240 goto winCreateHardLinkRetry;
3241
3242 return rc;
3243}
3244
3245int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003246CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003247 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003248 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249{
3250/* SMB_QUERY_FILE_UNIX_LINK */
3251 TRANSACTION2_QPI_REQ *pSMB = NULL;
3252 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3253 int rc = 0;
3254 int bytes_returned;
3255 int name_len;
3256 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003257 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Joe Perchesf96637b2013-05-04 22:12:25 -05003259 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
3261querySymLinkRetry:
3262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3263 (void **) &pSMBr);
3264 if (rc)
3265 return rc;
3266
3267 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3268 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003269 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3270 searchName, PATH_MAX, nls_codepage,
3271 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 name_len++; /* trailing null */
3273 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003274 } else {
3275 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
3277
3278 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3279 pSMB->TotalDataCount = 0;
3280 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003281 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 pSMB->MaxSetupCount = 0;
3283 pSMB->Reserved = 0;
3284 pSMB->Flags = 0;
3285 pSMB->Timeout = 0;
3286 pSMB->Reserved2 = 0;
3287 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003288 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 pSMB->DataCount = 0;
3290 pSMB->DataOffset = 0;
3291 pSMB->SetupCount = 1;
3292 pSMB->Reserved3 = 0;
3293 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3294 byte_count = params + 1 /* pad */ ;
3295 pSMB->TotalParameterCount = cpu_to_le16(params);
3296 pSMB->ParameterCount = pSMB->TotalParameterCount;
3297 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3298 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003299 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 pSMB->ByteCount = cpu_to_le16(byte_count);
3301
3302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3304 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003305 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 } else {
3307 /* decode response */
3308
3309 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003311 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003312 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003314 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003315 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Jeff Layton460b9692009-04-30 07:17:56 -04003317 data_start = ((char *) &pSMBr->hdr.Protocol) +
3318 le16_to_cpu(pSMBr->t2.DataOffset);
3319
Steve French0e0d2cf2009-05-01 05:27:32 +00003320 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3321 is_unicode = true;
3322 else
3323 is_unicode = false;
3324
Steve French737b7582005-04-28 22:41:06 -07003325 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003326 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3327 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003328 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003329 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 }
3331 }
3332 cifs_buf_release(pSMB);
3333 if (rc == -EAGAIN)
3334 goto querySymLinkRetry;
3335 return rc;
3336}
3337
Steve Frenchc52a95542011-02-24 06:16:22 +00003338/*
3339 * Recent Windows versions now create symlinks more frequently
3340 * and they use the "reparse point" mechanism below. We can of course
3341 * do symlinks nicely to Samba and other servers which support the
3342 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3343 * "MF" symlinks optionally, but for recent Windows we really need to
3344 * reenable the code below and fix the cifs_symlink callers to handle this.
3345 * In the interim this code has been moved to its own config option so
3346 * it is not compiled in by default until callers fixed up and more tested.
3347 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003349CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3350 __u16 fid, char **symlinkinfo,
3351 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 int rc = 0;
3354 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003355 struct smb_com_transaction_ioctl_req *pSMB;
3356 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003357 bool is_unicode;
3358 unsigned int sub_len;
3359 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003360 struct reparse_symlink_data *reparse_buf;
3361 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003362 __u32 data_offset, data_count;
3363 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003365 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3367 (void **) &pSMBr);
3368 if (rc)
3369 return rc;
3370
3371 pSMB->TotalParameterCount = 0 ;
3372 pSMB->TotalDataCount = 0;
3373 pSMB->MaxParameterCount = cpu_to_le32(2);
3374 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003375 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 pSMB->MaxSetupCount = 4;
3377 pSMB->Reserved = 0;
3378 pSMB->ParameterOffset = 0;
3379 pSMB->DataCount = 0;
3380 pSMB->DataOffset = 0;
3381 pSMB->SetupCount = 4;
3382 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3383 pSMB->ParameterCount = pSMB->TotalParameterCount;
3384 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3385 pSMB->IsFsctl = 1; /* FSCTL */
3386 pSMB->IsRootFlag = 0;
3387 pSMB->Fid = fid; /* file handle always le */
3388 pSMB->ByteCount = 0;
3389
3390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3392 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003393 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003394 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 }
Steve French989c7e52009-05-02 05:32:20 +00003396
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003397 data_offset = le32_to_cpu(pSMBr->DataOffset);
3398 data_count = le32_to_cpu(pSMBr->DataCount);
3399 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3400 /* BB also check enough total bytes returned */
3401 rc = -EIO; /* bad smb */
3402 goto qreparse_out;
3403 }
3404 if (!data_count || (data_count > 2048)) {
3405 rc = -EIO;
3406 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3407 goto qreparse_out;
3408 }
3409 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003410 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003411 ((char *)&pSMBr->hdr.Protocol + data_offset);
3412 if ((char *)reparse_buf >= end_of_smb) {
3413 rc = -EIO;
3414 goto qreparse_out;
3415 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003416 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3417 cifs_dbg(FYI, "NFS style reparse tag\n");
3418 posix_buf = (struct reparse_posix_data *)reparse_buf;
3419
3420 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3421 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3422 le64_to_cpu(posix_buf->InodeType));
3423 rc = -EOPNOTSUPP;
3424 goto qreparse_out;
3425 }
3426 is_unicode = true;
3427 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3428 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3429 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3430 rc = -EIO;
3431 goto qreparse_out;
3432 }
3433 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3434 sub_len, is_unicode, nls_codepage);
3435 goto qreparse_out;
3436 } else if (reparse_buf->ReparseTag !=
3437 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3438 rc = -EOPNOTSUPP;
3439 goto qreparse_out;
3440 }
3441
3442 /* Reparse tag is NTFS symlink */
3443 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3444 reparse_buf->PathBuffer;
3445 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3446 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003447 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3448 rc = -EIO;
3449 goto qreparse_out;
3450 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003451 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3452 is_unicode = true;
3453 else
3454 is_unicode = false;
3455
3456 /* BB FIXME investigate remapping reserved chars here */
3457 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3458 nls_codepage);
3459 if (!*symlinkinfo)
3460 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003462 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003464 /*
3465 * Note: On -EAGAIN error only caller can retry on handle based calls
3466 * since file handle passed in no longer valid.
3467 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 return rc;
3469}
3470
Steve Frenchc7f508a2013-10-14 15:27:32 -05003471int
3472CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3473 __u16 fid)
3474{
3475 int rc = 0;
3476 int bytes_returned;
3477 struct smb_com_transaction_compr_ioctl_req *pSMB;
3478 struct smb_com_transaction_ioctl_rsp *pSMBr;
3479
3480 cifs_dbg(FYI, "Set compression for %u\n", fid);
3481 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3482 (void **) &pSMBr);
3483 if (rc)
3484 return rc;
3485
3486 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3487
3488 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003489 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003490 pSMB->MaxParameterCount = 0;
3491 pSMB->MaxDataCount = 0;
3492 pSMB->MaxSetupCount = 4;
3493 pSMB->Reserved = 0;
3494 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003495 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003496 pSMB->DataOffset =
3497 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3498 compression_state) - 4); /* 84 */
3499 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003500 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003501 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003502 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003503 pSMB->IsFsctl = 1; /* FSCTL */
3504 pSMB->IsRootFlag = 0;
3505 pSMB->Fid = fid; /* file handle always le */
3506 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003507 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003508 inc_rfc1001_len(pSMB, 5);
3509
3510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3512 if (rc)
3513 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3514
3515 cifs_buf_release(pSMB);
3516
3517 /*
3518 * Note: On -EAGAIN error only caller can retry on handle based calls
3519 * since file handle passed in no longer valid.
3520 */
3521 return rc;
3522}
3523
3524
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525#ifdef CONFIG_CIFS_POSIX
3526
3527/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003528static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003529 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530{
3531 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003532 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3533 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3534 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003535/*
3536 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3537 ace->e_perm, ace->e_tag, ace->e_id);
3538*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539
3540 return;
3541}
3542
3543/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003544static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3545 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546{
3547 int size = 0;
3548 int i;
3549 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003550 struct cifs_posix_ace *pACE;
3551 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003552 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
3554 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3555 return -EOPNOTSUPP;
3556
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003557 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 count = le16_to_cpu(cifs_acl->access_entry_count);
3559 pACE = &cifs_acl->ace_array[0];
3560 size = sizeof(struct cifs_posix_acl);
3561 size += sizeof(struct cifs_posix_ace) * count;
3562 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003563 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003564 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3565 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 return -EINVAL;
3567 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003568 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 count = le16_to_cpu(cifs_acl->access_entry_count);
3570 size = sizeof(struct cifs_posix_acl);
3571 size += sizeof(struct cifs_posix_ace) * count;
3572/* skip past access ACEs to get to default ACEs */
3573 pACE = &cifs_acl->ace_array[count];
3574 count = le16_to_cpu(cifs_acl->default_entry_count);
3575 size += sizeof(struct cifs_posix_ace) * count;
3576 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003577 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 return -EINVAL;
3579 } else {
3580 /* illegal type */
3581 return -EINVAL;
3582 }
3583
3584 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003585 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003586 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003587 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 return -ERANGE;
3589 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003590 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3591
Steve Frenchff7feac2005-11-15 16:45:16 -08003592 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003593 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003594 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003595 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 }
3597 }
3598 return size;
3599}
3600
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303601static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003602 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603{
Steve Frenchff7feac2005-11-15 16:45:16 -08003604 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3605 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003607 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 /* Probably no need to le convert -1 on any arch but can not hurt */
3609 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003610 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003611 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003612/*
3613 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3614 ace->e_perm, ace->e_tag, ace->e_id);
3615*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616}
3617
3618/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003619static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3620 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621{
3622 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003623 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003624 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003625 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 int count;
3627 int i;
3628
Steve French790fe572007-07-07 19:25:05 +00003629 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 return 0;
3631
3632 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003633 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3634 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003635 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003636 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3637 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 return 0;
3639 }
3640 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003641 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003642 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003643 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003644 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003645 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003646 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003647 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003648 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 return 0;
3650 }
Hariprasad Kelam0aa3a242019-07-02 23:50:02 +05303651 for (i = 0; i < count; i++)
3652 convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003653 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3655 rc += sizeof(struct cifs_posix_acl);
3656 /* BB add check to make sure ACL does not overflow SMB */
3657 }
3658 return rc;
3659}
3660
3661int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003662CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003663 const unsigned char *searchName,
3664 char *acl_inf, const int buflen, const int acl_type,
3665 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666{
3667/* SMB_QUERY_POSIX_ACL */
3668 TRANSACTION2_QPI_REQ *pSMB = NULL;
3669 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3670 int rc = 0;
3671 int bytes_returned;
3672 int name_len;
3673 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003674
Joe Perchesf96637b2013-05-04 22:12:25 -05003675 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
3677queryAclRetry:
3678 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3679 (void **) &pSMBr);
3680 if (rc)
3681 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003682
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3684 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003685 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3686 searchName, PATH_MAX, nls_codepage,
3687 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 name_len++; /* trailing null */
3689 name_len *= 2;
3690 pSMB->FileName[name_len] = 0;
3691 pSMB->FileName[name_len+1] = 0;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003692 } else {
3693 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 }
3695
3696 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3697 pSMB->TotalDataCount = 0;
3698 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003699 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 pSMB->MaxDataCount = cpu_to_le16(4000);
3701 pSMB->MaxSetupCount = 0;
3702 pSMB->Reserved = 0;
3703 pSMB->Flags = 0;
3704 pSMB->Timeout = 0;
3705 pSMB->Reserved2 = 0;
3706 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003707 offsetof(struct smb_com_transaction2_qpi_req,
3708 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 pSMB->DataCount = 0;
3710 pSMB->DataOffset = 0;
3711 pSMB->SetupCount = 1;
3712 pSMB->Reserved3 = 0;
3713 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3714 byte_count = params + 1 /* pad */ ;
3715 pSMB->TotalParameterCount = cpu_to_le16(params);
3716 pSMB->ParameterCount = pSMB->TotalParameterCount;
3717 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3718 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003719 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 pSMB->ByteCount = cpu_to_le16(byte_count);
3721
3722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003724 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003726 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 } else {
3728 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003729
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003732 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 rc = -EIO; /* bad smb */
3734 else {
3735 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3736 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3737 rc = cifs_copy_posix_acl(acl_inf,
3738 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003739 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 }
3741 }
3742 cifs_buf_release(pSMB);
3743 if (rc == -EAGAIN)
3744 goto queryAclRetry;
3745 return rc;
3746}
3747
3748int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003749CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003750 const unsigned char *fileName,
3751 const char *local_acl, const int buflen,
3752 const int acl_type,
3753 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754{
3755 struct smb_com_transaction2_spi_req *pSMB = NULL;
3756 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3757 char *parm_data;
3758 int name_len;
3759 int rc = 0;
3760 int bytes_returned = 0;
3761 __u16 params, byte_count, data_count, param_offset, offset;
3762
Joe Perchesf96637b2013-05-04 22:12:25 -05003763 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764setAclRetry:
3765 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003766 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 if (rc)
3768 return rc;
3769 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3770 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003771 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3772 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 name_len++; /* trailing null */
3774 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10003775 } else {
3776 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 }
3778 params = 6 + name_len;
3779 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003780 /* BB find max SMB size from sess */
3781 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 pSMB->MaxSetupCount = 0;
3783 pSMB->Reserved = 0;
3784 pSMB->Flags = 0;
3785 pSMB->Timeout = 0;
3786 pSMB->Reserved2 = 0;
3787 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003788 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 offset = param_offset + params;
3790 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3791 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3792
3793 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003794 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795
Steve French790fe572007-07-07 19:25:05 +00003796 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 rc = -EOPNOTSUPP;
3798 goto setACLerrorExit;
3799 }
3800 pSMB->DataOffset = cpu_to_le16(offset);
3801 pSMB->SetupCount = 1;
3802 pSMB->Reserved3 = 0;
3803 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3804 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3805 byte_count = 3 /* pad */ + params + data_count;
3806 pSMB->DataCount = cpu_to_le16(data_count);
3807 pSMB->TotalDataCount = pSMB->DataCount;
3808 pSMB->ParameterCount = cpu_to_le16(params);
3809 pSMB->TotalParameterCount = pSMB->ParameterCount;
3810 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003811 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 pSMB->ByteCount = cpu_to_le16(byte_count);
3813 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003815 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003816 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
3818setACLerrorExit:
3819 cifs_buf_release(pSMB);
3820 if (rc == -EAGAIN)
3821 goto setAclRetry;
3822 return rc;
3823}
3824
Steve Frenchf654bac2005-04-28 22:41:04 -07003825/* BB fix tabs in this function FIXME BB */
3826int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003827CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003828 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003829{
Steve French50c2f752007-07-13 00:33:32 +00003830 int rc = 0;
3831 struct smb_t2_qfi_req *pSMB = NULL;
3832 struct smb_t2_qfi_rsp *pSMBr = NULL;
3833 int bytes_returned;
3834 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003835
Joe Perchesf96637b2013-05-04 22:12:25 -05003836 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003837 if (tcon == NULL)
3838 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003839
3840GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003841 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3842 (void **) &pSMBr);
3843 if (rc)
3844 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003845
Steve Frenchad7a2922008-02-07 23:25:02 +00003846 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003847 pSMB->t2.TotalDataCount = 0;
3848 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3849 /* BB find exact max data count below from sess structure BB */
3850 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3851 pSMB->t2.MaxSetupCount = 0;
3852 pSMB->t2.Reserved = 0;
3853 pSMB->t2.Flags = 0;
3854 pSMB->t2.Timeout = 0;
3855 pSMB->t2.Reserved2 = 0;
3856 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3857 Fid) - 4);
3858 pSMB->t2.DataCount = 0;
3859 pSMB->t2.DataOffset = 0;
3860 pSMB->t2.SetupCount = 1;
3861 pSMB->t2.Reserved3 = 0;
3862 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3863 byte_count = params + 1 /* pad */ ;
3864 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3865 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3866 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3867 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003868 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003869 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003870 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003871
Steve French790fe572007-07-07 19:25:05 +00003872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3874 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003875 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003876 } else {
3877 /* decode response */
3878 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003879 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003880 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003881 /* If rc should we check for EOPNOSUPP and
3882 disable the srvino flag? or in caller? */
3883 rc = -EIO; /* bad smb */
3884 else {
3885 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3886 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3887 struct file_chattr_info *pfinfo;
3888 /* BB Do we need a cast or hash here ? */
3889 if (count != 16) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003890 cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003891 rc = -EIO;
3892 goto GetExtAttrOut;
3893 }
3894 pfinfo = (struct file_chattr_info *)
3895 (data_offset + (char *) &pSMBr->hdr.Protocol);
3896 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003897 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003898 }
3899 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003900GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003901 cifs_buf_release(pSMB);
3902 if (rc == -EAGAIN)
3903 goto GetExtAttrRetry;
3904 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003905}
3906
Steve Frenchf654bac2005-04-28 22:41:04 -07003907#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
Jeff Layton79df1ba2010-12-06 12:52:08 -05003909/*
3910 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3911 * all NT TRANSACTS that we init here have total parm and data under about 400
3912 * bytes (to fit in small cifs buffer size), which is the case so far, it
3913 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3914 * returned setup area) and MaxParameterCount (returned parms size) must be set
3915 * by caller
3916 */
3917static int
3918smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003919 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003920 void **ret_buf)
3921{
3922 int rc;
3923 __u32 temp_offset;
3924 struct smb_com_ntransact_req *pSMB;
3925
3926 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3927 (void **)&pSMB);
3928 if (rc)
3929 return rc;
3930 *ret_buf = (void *)pSMB;
3931 pSMB->Reserved = 0;
3932 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3933 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003934 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003935 pSMB->ParameterCount = pSMB->TotalParameterCount;
3936 pSMB->DataCount = pSMB->TotalDataCount;
3937 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3938 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3939 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3940 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3941 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3942 pSMB->SubCommand = cpu_to_le16(sub_command);
3943 return 0;
3944}
3945
3946static int
3947validate_ntransact(char *buf, char **ppparm, char **ppdata,
3948 __u32 *pparmlen, __u32 *pdatalen)
3949{
3950 char *end_of_smb;
3951 __u32 data_count, data_offset, parm_count, parm_offset;
3952 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003953 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003954
3955 *pdatalen = 0;
3956 *pparmlen = 0;
3957
3958 if (buf == NULL)
3959 return -EINVAL;
3960
3961 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3962
Jeff Layton820a8032011-05-04 08:05:26 -04003963 bcc = get_bcc(&pSMBr->hdr);
3964 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003965 (char *)&pSMBr->ByteCount;
3966
3967 data_offset = le32_to_cpu(pSMBr->DataOffset);
3968 data_count = le32_to_cpu(pSMBr->DataCount);
3969 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3970 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3971
3972 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3973 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3974
3975 /* should we also check that parm and data areas do not overlap? */
3976 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003977 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003978 return -EINVAL;
3979 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003980 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003981 return -EINVAL;
3982 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003983 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003984 return -EINVAL;
3985 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003986 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3987 *ppdata, data_count, (data_count + *ppdata),
3988 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003989 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003990 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003991 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003992 return -EINVAL;
3993 }
3994 *pdatalen = data_count;
3995 *pparmlen = parm_count;
3996 return 0;
3997}
3998
Steve French0a4b92c2006-01-12 15:44:21 -08003999/* Get Security Descriptor (by handle) from remote server for a file or dir */
4000int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004001CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00004002 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08004003{
4004 int rc = 0;
4005 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00004006 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08004007 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004008 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08004009
Joe Perchesf96637b2013-05-04 22:12:25 -05004010 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08004011
Steve French630f3f0c2007-10-25 21:17:17 +00004012 *pbuflen = 0;
4013 *acl_inf = NULL;
4014
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00004015 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08004016 8 /* parm len */, tcon, (void **) &pSMB);
4017 if (rc)
4018 return rc;
4019
4020 pSMB->MaxParameterCount = cpu_to_le32(4);
4021 /* BB TEST with big acls that might need to be e.g. larger than 16K */
4022 pSMB->MaxSetupCount = 0;
4023 pSMB->Fid = fid; /* file handle always le */
4024 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
4025 CIFS_ACL_DACL);
4026 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004027 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08004028 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004029 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08004030
Steve Frencha761ac52007-10-18 21:45:27 +00004031 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004032 0, &rsp_iov);
4033 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004034 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08004035 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004036 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08004037 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00004038 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00004039 __u32 parm_len;
4040 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00004041 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00004042 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08004043
4044/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004045 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00004046 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00004047 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08004048 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004049 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08004050
Joe Perchesf96637b2013-05-04 22:12:25 -05004051 cifs_dbg(FYI, "smb %p parm %p data %p\n",
4052 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08004053
4054 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
4055 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00004056 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08004057 goto qsec_out;
4058 }
4059
4060/* BB check that data area is minimum length and as big as acl_len */
4061
Steve Frenchaf6f4612007-10-16 18:40:37 +00004062 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00004063 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004064 cifs_dbg(VFS, "acl length %d does not match %d\n",
4065 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004066 if (*pbuflen > acl_len)
4067 *pbuflen = acl_len;
4068 }
Steve French0a4b92c2006-01-12 15:44:21 -08004069
Steve French630f3f0c2007-10-25 21:17:17 +00004070 /* check if buffer is big enough for the acl
4071 header followed by the smallest SID */
4072 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
4073 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004074 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00004075 rc = -EINVAL;
4076 *pbuflen = 0;
4077 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02004078 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00004079 if (*acl_inf == NULL) {
4080 *pbuflen = 0;
4081 rc = -ENOMEM;
4082 }
Steve French630f3f0c2007-10-25 21:17:17 +00004083 }
Steve French0a4b92c2006-01-12 15:44:21 -08004084 }
4085qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004086 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08004087 return rc;
4088}
Steve French97837582007-12-31 07:47:21 +00004089
4090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004091CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004092 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00004093{
4094 __u16 byte_count, param_count, data_count, param_offset, data_offset;
4095 int rc = 0;
4096 int bytes_returned = 0;
4097 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004098 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00004099
4100setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004101 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00004102 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004103 return rc;
Steve French97837582007-12-31 07:47:21 +00004104
4105 pSMB->MaxSetupCount = 0;
4106 pSMB->Reserved = 0;
4107
4108 param_count = 8;
4109 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4110 data_count = acllen;
4111 data_offset = param_offset + param_count;
4112 byte_count = 3 /* pad */ + param_count;
4113
4114 pSMB->DataCount = cpu_to_le32(data_count);
4115 pSMB->TotalDataCount = pSMB->DataCount;
4116 pSMB->MaxParameterCount = cpu_to_le32(4);
4117 pSMB->MaxDataCount = cpu_to_le32(16384);
4118 pSMB->ParameterCount = cpu_to_le32(param_count);
4119 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4120 pSMB->TotalParameterCount = pSMB->ParameterCount;
4121 pSMB->DataOffset = cpu_to_le32(data_offset);
4122 pSMB->SetupCount = 0;
4123 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4124 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4125
4126 pSMB->Fid = fid; /* file handle always le */
4127 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004128 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004129
4130 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004131 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4132 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004133 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004134 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004135 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004136
4137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4139
Joe Perchesf96637b2013-05-04 22:12:25 -05004140 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4141 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004142 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004143 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004144 cifs_buf_release(pSMB);
4145
4146 if (rc == -EAGAIN)
4147 goto setCifsAclRetry;
4148
4149 return (rc);
4150}
4151
Steve French0a4b92c2006-01-12 15:44:21 -08004152
Steve French6b8edfe2005-08-23 20:26:03 -07004153/* Legacy Query Path Information call for lookup to old servers such
4154 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004155int
4156SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4157 const char *search_name, FILE_ALL_INFO *data,
4158 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004159{
Steve Frenchad7a2922008-02-07 23:25:02 +00004160 QUERY_INFORMATION_REQ *pSMB;
4161 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004162 int rc = 0;
4163 int bytes_returned;
4164 int name_len;
4165
Joe Perchesf96637b2013-05-04 22:12:25 -05004166 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004167QInfRetry:
4168 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004169 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004170 if (rc)
4171 return rc;
4172
4173 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4174 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004175 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004176 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004177 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004178 name_len++; /* trailing null */
4179 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004180 } else {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004181 name_len = copy_path_name(pSMB->FileName, search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004182 }
4183 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004184 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004185 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004186 pSMB->ByteCount = cpu_to_le16(name_len);
4187
4188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004190 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004191 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004192 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004193 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004194 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004195
4196 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004197 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004198 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004199 ts.tv_nsec = 0;
4200 ts.tv_sec = time;
4201 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004202 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4203 data->LastWriteTime = data->ChangeTime;
4204 data->LastAccessTime = 0;
4205 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004206 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004207 data->EndOfFile = data->AllocationSize;
4208 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004209 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004210 } else
4211 rc = -EIO; /* bad buffer passed in */
4212
4213 cifs_buf_release(pSMB);
4214
4215 if (rc == -EAGAIN)
4216 goto QInfRetry;
4217
4218 return rc;
4219}
4220
Jeff Laytonbcd53572010-02-12 07:44:16 -05004221int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004222CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004223 u16 netfid, FILE_ALL_INFO *pFindData)
4224{
4225 struct smb_t2_qfi_req *pSMB = NULL;
4226 struct smb_t2_qfi_rsp *pSMBr = NULL;
4227 int rc = 0;
4228 int bytes_returned;
4229 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004230
Jeff Laytonbcd53572010-02-12 07:44:16 -05004231QFileInfoRetry:
4232 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4233 (void **) &pSMBr);
4234 if (rc)
4235 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004236
Jeff Laytonbcd53572010-02-12 07:44:16 -05004237 params = 2 /* level */ + 2 /* fid */;
4238 pSMB->t2.TotalDataCount = 0;
4239 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4240 /* BB find exact max data count below from sess structure BB */
4241 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4242 pSMB->t2.MaxSetupCount = 0;
4243 pSMB->t2.Reserved = 0;
4244 pSMB->t2.Flags = 0;
4245 pSMB->t2.Timeout = 0;
4246 pSMB->t2.Reserved2 = 0;
4247 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4248 Fid) - 4);
4249 pSMB->t2.DataCount = 0;
4250 pSMB->t2.DataOffset = 0;
4251 pSMB->t2.SetupCount = 1;
4252 pSMB->t2.Reserved3 = 0;
4253 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4254 byte_count = params + 1 /* pad */ ;
4255 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4256 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4257 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4258 pSMB->Pad = 0;
4259 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004260 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004261 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004262
4263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4265 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004266 cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004267 } else { /* decode response */
4268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4269
4270 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4271 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004272 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004273 rc = -EIO; /* bad smb */
4274 else if (pFindData) {
4275 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4276 memcpy((char *) pFindData,
4277 (char *) &pSMBr->hdr.Protocol +
4278 data_offset, sizeof(FILE_ALL_INFO));
4279 } else
4280 rc = -ENOMEM;
4281 }
4282 cifs_buf_release(pSMB);
4283 if (rc == -EAGAIN)
4284 goto QFileInfoRetry;
4285
4286 return rc;
4287}
Steve French6b8edfe2005-08-23 20:26:03 -07004288
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004290CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004291 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004292 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004293 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004295 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 TRANSACTION2_QPI_REQ *pSMB = NULL;
4297 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4298 int rc = 0;
4299 int bytes_returned;
4300 int name_len;
4301 __u16 params, byte_count;
4302
Joe Perchesf96637b2013-05-04 22:12:25 -05004303 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304QPathInfoRetry:
4305 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4306 (void **) &pSMBr);
4307 if (rc)
4308 return rc;
4309
4310 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4311 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004312 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004313 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 name_len++; /* trailing null */
4315 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004316 } else {
4317 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 }
4319
Steve French50c2f752007-07-13 00:33:32 +00004320 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004323 /* BB find exact max SMB PDU from sess structure BB */
4324 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 pSMB->MaxSetupCount = 0;
4326 pSMB->Reserved = 0;
4327 pSMB->Flags = 0;
4328 pSMB->Timeout = 0;
4329 pSMB->Reserved2 = 0;
4330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 pSMB->DataCount = 0;
4333 pSMB->DataOffset = 0;
4334 pSMB->SetupCount = 1;
4335 pSMB->Reserved3 = 0;
4336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4337 byte_count = params + 1 /* pad */ ;
4338 pSMB->TotalParameterCount = cpu_to_le16(params);
4339 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004340 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004341 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4342 else
4343 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004345 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 pSMB->ByteCount = cpu_to_le16(byte_count);
4347
4348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4350 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004351 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 } else { /* decode response */
4353 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4354
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004355 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4356 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004357 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004359 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004360 rc = -EIO; /* 24 or 26 expected but we do not read
4361 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004362 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004363 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004365
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004366 /*
4367 * On legacy responses we do not read the last field,
4368 * EAsize, fortunately since it varies by subdialect and
4369 * also note it differs on Set vs Get, ie two bytes or 4
4370 * bytes depending but we don't care here.
4371 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004372 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004373 size = sizeof(FILE_INFO_STANDARD);
4374 else
4375 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004376 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004377 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 } else
4379 rc = -ENOMEM;
4380 }
4381 cifs_buf_release(pSMB);
4382 if (rc == -EAGAIN)
4383 goto QPathInfoRetry;
4384
4385 return rc;
4386}
4387
4388int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004389CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004390 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4391{
4392 struct smb_t2_qfi_req *pSMB = NULL;
4393 struct smb_t2_qfi_rsp *pSMBr = NULL;
4394 int rc = 0;
4395 int bytes_returned;
4396 __u16 params, byte_count;
4397
4398UnixQFileInfoRetry:
4399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4400 (void **) &pSMBr);
4401 if (rc)
4402 return rc;
4403
4404 params = 2 /* level */ + 2 /* fid */;
4405 pSMB->t2.TotalDataCount = 0;
4406 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4407 /* BB find exact max data count below from sess structure BB */
4408 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4409 pSMB->t2.MaxSetupCount = 0;
4410 pSMB->t2.Reserved = 0;
4411 pSMB->t2.Flags = 0;
4412 pSMB->t2.Timeout = 0;
4413 pSMB->t2.Reserved2 = 0;
4414 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4415 Fid) - 4);
4416 pSMB->t2.DataCount = 0;
4417 pSMB->t2.DataOffset = 0;
4418 pSMB->t2.SetupCount = 1;
4419 pSMB->t2.Reserved3 = 0;
4420 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4421 byte_count = params + 1 /* pad */ ;
4422 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4423 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4424 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4425 pSMB->Pad = 0;
4426 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004427 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004428 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004429
4430 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4431 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4432 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004433 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004434 } else { /* decode response */
4435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4436
Jeff Layton820a8032011-05-04 08:05:26 -04004437 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004438 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 -05004439 rc = -EIO; /* bad smb */
4440 } else {
4441 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4442 memcpy((char *) pFindData,
4443 (char *) &pSMBr->hdr.Protocol +
4444 data_offset,
4445 sizeof(FILE_UNIX_BASIC_INFO));
4446 }
4447 }
4448
4449 cifs_buf_release(pSMB);
4450 if (rc == -EAGAIN)
4451 goto UnixQFileInfoRetry;
4452
4453 return rc;
4454}
4455
4456int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004457CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004459 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004460 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461{
4462/* SMB_QUERY_FILE_UNIX_BASIC */
4463 TRANSACTION2_QPI_REQ *pSMB = NULL;
4464 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4465 int rc = 0;
4466 int bytes_returned = 0;
4467 int name_len;
4468 __u16 params, byte_count;
4469
Joe Perchesf96637b2013-05-04 22:12:25 -05004470 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471UnixQPathInfoRetry:
4472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4473 (void **) &pSMBr);
4474 if (rc)
4475 return rc;
4476
4477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4478 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004479 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4480 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 name_len++; /* trailing null */
4482 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004483 } else {
4484 name_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
4486
Steve French50c2f752007-07-13 00:33:32 +00004487 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 pSMB->TotalDataCount = 0;
4489 pSMB->MaxParameterCount = cpu_to_le16(2);
4490 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004491 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->MaxSetupCount = 0;
4493 pSMB->Reserved = 0;
4494 pSMB->Flags = 0;
4495 pSMB->Timeout = 0;
4496 pSMB->Reserved2 = 0;
4497 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004498 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 pSMB->DataCount = 0;
4500 pSMB->DataOffset = 0;
4501 pSMB->SetupCount = 1;
4502 pSMB->Reserved3 = 0;
4503 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4504 byte_count = params + 1 /* pad */ ;
4505 pSMB->TotalParameterCount = cpu_to_le16(params);
4506 pSMB->ParameterCount = pSMB->TotalParameterCount;
4507 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4508 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004509 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 pSMB->ByteCount = cpu_to_le16(byte_count);
4511
4512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4513 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4514 if (rc) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004515 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 } else { /* decode response */
4517 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4518
Jeff Layton820a8032011-05-04 08:05:26 -04004519 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004520 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 -07004521 rc = -EIO; /* bad smb */
4522 } else {
4523 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4524 memcpy((char *) pFindData,
4525 (char *) &pSMBr->hdr.Protocol +
4526 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004527 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 }
4529 }
4530 cifs_buf_release(pSMB);
4531 if (rc == -EAGAIN)
4532 goto UnixQPathInfoRetry;
4533
4534 return rc;
4535}
4536
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537/* xid, tcon, searchName and codepage are input parms, rest are returned */
4538int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004539CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004540 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004541 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004542 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543{
4544/* level 257 SMB_ */
4545 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4546 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004547 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 int rc = 0;
4549 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004550 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004552 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
Joe Perchesf96637b2013-05-04 22:12:25 -05004554 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
4556findFirstRetry:
4557 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4558 (void **) &pSMBr);
4559 if (rc)
4560 return rc;
4561
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004562 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004563 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4566 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004567 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4568 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004569 /* We can not add the asterik earlier in case
4570 it got remapped to 0xF03A as if it were part of the
4571 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004573 if (msearch) {
4574 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4575 pSMB->FileName[name_len+1] = 0;
4576 pSMB->FileName[name_len+2] = '*';
4577 pSMB->FileName[name_len+3] = 0;
4578 name_len += 4; /* now the trailing null */
4579 /* null terminate just in case */
4580 pSMB->FileName[name_len] = 0;
4581 pSMB->FileName[name_len+1] = 0;
4582 name_len += 2;
4583 }
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004584 } else {
4585 name_len = copy_path_name(pSMB->FileName, searchName);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004586 if (msearch) {
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004587 if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4588 name_len = PATH_MAX-2;
4589 /* overwrite nul byte */
4590 pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4591 pSMB->FileName[name_len] = '*';
4592 pSMB->FileName[name_len+1] = 0;
4593 name_len += 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 }
4596
4597 params = 12 + name_len /* includes null */ ;
4598 pSMB->TotalDataCount = 0; /* no EAs */
4599 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004600 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->MaxSetupCount = 0;
4602 pSMB->Reserved = 0;
4603 pSMB->Flags = 0;
4604 pSMB->Timeout = 0;
4605 pSMB->Reserved2 = 0;
4606 byte_count = params + 1 /* pad */ ;
4607 pSMB->TotalParameterCount = cpu_to_le16(params);
4608 pSMB->ParameterCount = pSMB->TotalParameterCount;
4609 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004610 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4611 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 pSMB->DataCount = 0;
4613 pSMB->DataOffset = 0;
4614 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4615 pSMB->Reserved3 = 0;
4616 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4617 pSMB->SearchAttributes =
4618 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4619 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004620 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004621 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4623
4624 /* BB what should we set StorageType to? Does it matter? BB */
4625 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004626 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 pSMB->ByteCount = cpu_to_le16(byte_count);
4628
4629 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4630 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004631 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
Steve French88274812006-03-09 22:21:45 +00004633 if (rc) {/* BB add logic to retry regular search if Unix search
4634 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004636 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004637
Steve French88274812006-03-09 22:21:45 +00004638 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639
4640 /* BB eventually could optimize out free and realloc of buf */
4641 /* for this case */
4642 if (rc == -EAGAIN)
4643 goto findFirstRetry;
4644 } else { /* decode response */
4645 /* BB remember to free buffer if error BB */
4646 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004647 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004648 unsigned int lnoff;
4649
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004651 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 else
Steve French4b18f2a2008-04-29 00:06:05 +00004653 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654
4655 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
zhengbin01d1bd72019-12-25 11:30:21 +08004656 psrch_inf->smallBuf = false;
Steve French50c2f752007-07-13 00:33:32 +00004657 psrch_inf->srch_entries_start =
4658 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4661 le16_to_cpu(pSMBr->t2.ParameterOffset));
4662
Steve French790fe572007-07-07 19:25:05 +00004663 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004664 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 else
Steve French4b18f2a2008-04-29 00:06:05 +00004666 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667
Steve French50c2f752007-07-13 00:33:32 +00004668 psrch_inf->entries_in_buffer =
4669 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004670 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004672 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004673 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004674 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004675 psrch_inf->last_entry = NULL;
4676 return rc;
4677 }
4678
Steve French0752f152008-10-07 20:03:33 +00004679 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004680 lnoff;
4681
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004682 if (pnetfid)
4683 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 } else {
4685 cifs_buf_release(pSMB);
4686 }
4687 }
4688
4689 return rc;
4690}
4691
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004692int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4693 __u16 searchHandle, __u16 search_flags,
4694 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695{
4696 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4697 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004698 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 char *response_data;
4700 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004701 int bytes_returned;
4702 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 __u16 params, byte_count;
4704
Joe Perchesf96637b2013-05-04 22:12:25 -05004705 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Steve French4b18f2a2008-04-29 00:06:05 +00004707 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 return -ENOENT;
4709
4710 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4711 (void **) &pSMBr);
4712 if (rc)
4713 return rc;
4714
Steve French50c2f752007-07-13 00:33:32 +00004715 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 byte_count = 0;
4717 pSMB->TotalDataCount = 0; /* no EAs */
4718 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004719 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 pSMB->MaxSetupCount = 0;
4721 pSMB->Reserved = 0;
4722 pSMB->Flags = 0;
4723 pSMB->Timeout = 0;
4724 pSMB->Reserved2 = 0;
4725 pSMB->ParameterOffset = cpu_to_le16(
4726 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4727 pSMB->DataCount = 0;
4728 pSMB->DataOffset = 0;
4729 pSMB->SetupCount = 1;
4730 pSMB->Reserved3 = 0;
4731 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4732 pSMB->SearchHandle = searchHandle; /* always kept as le */
4733 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004734 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4736 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004737 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738
4739 name_len = psrch_inf->resume_name_len;
4740 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004741 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4743 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004744 /* 14 byte parm len above enough for 2 byte null terminator */
4745 pSMB->ResumeFileName[name_len] = 0;
4746 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 } else {
4748 rc = -EINVAL;
4749 goto FNext2_err_exit;
4750 }
4751 byte_count = params + 1 /* pad */ ;
4752 pSMB->TotalParameterCount = cpu_to_le16(params);
4753 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004754 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004756
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4758 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004759 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 if (rc) {
4761 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004762 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004763 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004764 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004766 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 } else { /* decode response */
4768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004769
Steve French790fe572007-07-07 19:25:05 +00004770 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004771 unsigned int lnoff;
4772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 /* BB fixme add lock for file (srch_info) struct here */
4774 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004775 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 else
Steve French4b18f2a2008-04-29 00:06:05 +00004777 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 response_data = (char *) &pSMBr->hdr.Protocol +
4779 le16_to_cpu(pSMBr->t2.ParameterOffset);
4780 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4781 response_data = (char *)&pSMBr->hdr.Protocol +
4782 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004783 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004784 cifs_small_buf_release(
4785 psrch_inf->ntwrk_buf_start);
4786 else
4787 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 psrch_inf->srch_entries_start = response_data;
4789 psrch_inf->ntwrk_buf_start = (char *)pSMB;
zhengbin01d1bd72019-12-25 11:30:21 +08004790 psrch_inf->smallBuf = false;
Steve French790fe572007-07-07 19:25:05 +00004791 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004792 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 else
Steve French4b18f2a2008-04-29 00:06:05 +00004794 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004795 psrch_inf->entries_in_buffer =
4796 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 psrch_inf->index_of_last_entry +=
4798 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004799 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004800 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004801 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004802 psrch_inf->last_entry = NULL;
4803 return rc;
4804 } else
4805 psrch_inf->last_entry =
4806 psrch_inf->srch_entries_start + lnoff;
4807
Joe Perchesf96637b2013-05-04 22:12:25 -05004808/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4809 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
4811 /* BB fixme add unlock here */
4812 }
4813
4814 }
4815
4816 /* BB On error, should we leave previous search buf (and count and
4817 last entry fields) intact or free the previous one? */
4818
4819 /* Note: On -EAGAIN error only caller can retry on handle based calls
4820 since file handle passed in no longer valid */
4821FNext2_err_exit:
4822 if (rc != 0)
4823 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 return rc;
4825}
4826
4827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004828CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004829 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830{
4831 int rc = 0;
4832 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Joe Perchesf96637b2013-05-04 22:12:25 -05004834 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4836
4837 /* no sense returning error if session restarted
4838 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004839 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 return 0;
4841 if (rc)
4842 return rc;
4843
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 pSMB->FileID = searchHandle;
4845 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004846 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004847 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004848 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004849 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004850
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004851 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
4853 /* Since session is dead, search handle closed on server already */
4854 if (rc == -EAGAIN)
4855 rc = 0;
4856
4857 return rc;
4858}
4859
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004861CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004862 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004863 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864{
4865 int rc = 0;
4866 TRANSACTION2_QPI_REQ *pSMB = NULL;
4867 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4868 int name_len, bytes_returned;
4869 __u16 params, byte_count;
4870
Joe Perchesf96637b2013-05-04 22:12:25 -05004871 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004872 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004873 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874
4875GetInodeNumberRetry:
4876 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004877 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 if (rc)
4879 return rc;
4880
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4882 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004883 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004884 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004885 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 name_len++; /* trailing null */
4887 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004888 } else {
4889 name_len = copy_path_name(pSMB->FileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 }
4891
4892 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4893 pSMB->TotalDataCount = 0;
4894 pSMB->MaxParameterCount = cpu_to_le16(2);
4895 /* BB find exact max data count below from sess structure BB */
4896 pSMB->MaxDataCount = cpu_to_le16(4000);
4897 pSMB->MaxSetupCount = 0;
4898 pSMB->Reserved = 0;
4899 pSMB->Flags = 0;
4900 pSMB->Timeout = 0;
4901 pSMB->Reserved2 = 0;
4902 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004903 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 pSMB->DataCount = 0;
4905 pSMB->DataOffset = 0;
4906 pSMB->SetupCount = 1;
4907 pSMB->Reserved3 = 0;
4908 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4909 byte_count = params + 1 /* pad */ ;
4910 pSMB->TotalParameterCount = cpu_to_le16(params);
4911 pSMB->ParameterCount = pSMB->TotalParameterCount;
4912 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4913 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004914 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 pSMB->ByteCount = cpu_to_le16(byte_count);
4916
4917 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4918 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4919 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004920 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 } else {
4922 /* decode response */
4923 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004925 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 /* If rc should we check for EOPNOSUPP and
4927 disable the srvino flag? or in caller? */
4928 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004929 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4931 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004932 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004934 if (count < 8) {
Joe Perchesa0a30362020-04-14 22:42:53 -07004935 cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 rc = -EIO;
4937 goto GetInodeNumOut;
4938 }
4939 pfinfo = (struct file_internal_info *)
4940 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004941 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 }
4943 }
4944GetInodeNumOut:
4945 cifs_buf_release(pSMB);
4946 if (rc == -EAGAIN)
4947 goto GetInodeNumberRetry;
4948 return rc;
4949}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950
4951int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004952CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004953 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004954 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004955 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956{
4957/* TRANS2_GET_DFS_REFERRAL */
4958 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4959 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 int rc = 0;
4961 int bytes_returned;
4962 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004964 *num_of_nodes = 0;
4965 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966
Joe Perchesf96637b2013-05-04 22:12:25 -05004967 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004968 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004970
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004972 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 (void **) &pSMBr);
4974 if (rc)
4975 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004976
4977 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004978 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004979 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004980 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004982 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004984 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986
4987 if (ses->capabilities & CAP_UNICODE) {
4988 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4989 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004990 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004991 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004992 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 name_len++; /* trailing null */
4994 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004995 } else { /* BB improve the check for buffer overruns BB */
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10004996 name_len = copy_path_name(pSMB->RequestFileName, search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 }
4998
Dan Carpenter65c3b202015-04-30 17:30:24 +03004999 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04005000 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00005001
Steve French50c2f752007-07-13 00:33:32 +00005002 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00005003
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 params = 2 /* level */ + name_len /*includes null */ ;
5005 pSMB->TotalDataCount = 0;
5006 pSMB->DataCount = 0;
5007 pSMB->DataOffset = 0;
5008 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00005009 /* BB find exact max SMB PDU from sess structure BB */
5010 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 pSMB->MaxSetupCount = 0;
5012 pSMB->Reserved = 0;
5013 pSMB->Flags = 0;
5014 pSMB->Timeout = 0;
5015 pSMB->Reserved2 = 0;
5016 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005017 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 pSMB->SetupCount = 1;
5019 pSMB->Reserved3 = 0;
5020 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
5021 byte_count = params + 3 /* pad */ ;
5022 pSMB->ParameterCount = cpu_to_le16(params);
5023 pSMB->TotalParameterCount = pSMB->ParameterCount;
5024 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005025 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 pSMB->ByteCount = cpu_to_le16(byte_count);
5027
5028 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
5029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5030 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005031 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005032 goto GetDFSRefExit;
5033 }
5034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005036 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04005037 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00005038 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04005039 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 }
Igor Mammedovfec45852008-05-16 13:06:30 +04005041
Joe Perchesf96637b2013-05-04 22:12:25 -05005042 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
5043 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04005044
5045 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01005046 rc = parse_dfs_referrals(&pSMBr->dfs_data,
5047 le16_to_cpu(pSMBr->t2.DataCount),
5048 num_of_nodes, target_nodes, nls_codepage,
5049 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06005050 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04005051
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00005053 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
5055 if (rc == -EAGAIN)
5056 goto getDFSRetry;
5057
5058 return rc;
5059}
5060
Steve French20962432005-09-21 22:05:57 -07005061/* Query File System Info such as free space to old servers such as Win 9x */
5062int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005063SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5064 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07005065{
5066/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
5067 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5068 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5069 FILE_SYSTEM_ALLOC_INFO *response_data;
5070 int rc = 0;
5071 int bytes_returned = 0;
5072 __u16 params, byte_count;
5073
Joe Perchesf96637b2013-05-04 22:12:25 -05005074 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07005075oldQFSInfoRetry:
5076 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5077 (void **) &pSMBr);
5078 if (rc)
5079 return rc;
Steve French20962432005-09-21 22:05:57 -07005080
5081 params = 2; /* level */
5082 pSMB->TotalDataCount = 0;
5083 pSMB->MaxParameterCount = cpu_to_le16(2);
5084 pSMB->MaxDataCount = cpu_to_le16(1000);
5085 pSMB->MaxSetupCount = 0;
5086 pSMB->Reserved = 0;
5087 pSMB->Flags = 0;
5088 pSMB->Timeout = 0;
5089 pSMB->Reserved2 = 0;
5090 byte_count = params + 1 /* pad */ ;
5091 pSMB->TotalParameterCount = cpu_to_le16(params);
5092 pSMB->ParameterCount = pSMB->TotalParameterCount;
5093 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5094 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5095 pSMB->DataCount = 0;
5096 pSMB->DataOffset = 0;
5097 pSMB->SetupCount = 1;
5098 pSMB->Reserved3 = 0;
5099 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5100 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005101 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005102 pSMB->ByteCount = cpu_to_le16(byte_count);
5103
5104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5106 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005107 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005108 } else { /* decode response */
5109 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5110
Jeff Layton820a8032011-05-04 08:05:26 -04005111 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005112 rc = -EIO; /* bad smb */
5113 else {
5114 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005115 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005116 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005117
Steve French50c2f752007-07-13 00:33:32 +00005118 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005119 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5120 FSData->f_bsize =
5121 le16_to_cpu(response_data->BytesPerSector) *
5122 le32_to_cpu(response_data->
5123 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005124 /*
5125 * much prefer larger but if server doesn't report
5126 * a valid size than 4K is a reasonable minimum
5127 */
5128 if (FSData->f_bsize < 512)
5129 FSData->f_bsize = 4096;
5130
Steve French20962432005-09-21 22:05:57 -07005131 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005132 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005133 FSData->f_bfree = FSData->f_bavail =
5134 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005135 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5136 (unsigned long long)FSData->f_blocks,
5137 (unsigned long long)FSData->f_bfree,
5138 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005139 }
5140 }
5141 cifs_buf_release(pSMB);
5142
5143 if (rc == -EAGAIN)
5144 goto oldQFSInfoRetry;
5145
5146 return rc;
5147}
5148
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005150CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5151 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
5153/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5154 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5155 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5156 FILE_SYSTEM_INFO *response_data;
5157 int rc = 0;
5158 int bytes_returned = 0;
5159 __u16 params, byte_count;
5160
Joe Perchesf96637b2013-05-04 22:12:25 -05005161 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162QFSInfoRetry:
5163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5164 (void **) &pSMBr);
5165 if (rc)
5166 return rc;
5167
5168 params = 2; /* level */
5169 pSMB->TotalDataCount = 0;
5170 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005171 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 pSMB->MaxSetupCount = 0;
5173 pSMB->Reserved = 0;
5174 pSMB->Flags = 0;
5175 pSMB->Timeout = 0;
5176 pSMB->Reserved2 = 0;
5177 byte_count = params + 1 /* pad */ ;
5178 pSMB->TotalParameterCount = cpu_to_le16(params);
5179 pSMB->ParameterCount = pSMB->TotalParameterCount;
5180 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005181 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 pSMB->DataCount = 0;
5183 pSMB->DataOffset = 0;
5184 pSMB->SetupCount = 1;
5185 pSMB->Reserved3 = 0;
5186 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5187 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005188 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 pSMB->ByteCount = cpu_to_le16(byte_count);
5190
5191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5193 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005194 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005196 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197
Jeff Layton820a8032011-05-04 08:05:26 -04005198 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 rc = -EIO; /* bad smb */
5200 else {
5201 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
5203 response_data =
5204 (FILE_SYSTEM_INFO
5205 *) (((char *) &pSMBr->hdr.Protocol) +
5206 data_offset);
5207 FSData->f_bsize =
5208 le32_to_cpu(response_data->BytesPerSector) *
5209 le32_to_cpu(response_data->
5210 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005211 /*
5212 * much prefer larger but if server doesn't report
5213 * a valid size than 4K is a reasonable minimum
5214 */
5215 if (FSData->f_bsize < 512)
5216 FSData->f_bsize = 4096;
5217
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 FSData->f_blocks =
5219 le64_to_cpu(response_data->TotalAllocationUnits);
5220 FSData->f_bfree = FSData->f_bavail =
5221 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005222 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5223 (unsigned long long)FSData->f_blocks,
5224 (unsigned long long)FSData->f_bfree,
5225 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 }
5227 }
5228 cifs_buf_release(pSMB);
5229
5230 if (rc == -EAGAIN)
5231 goto QFSInfoRetry;
5232
5233 return rc;
5234}
5235
5236int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005237CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238{
5239/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5240 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5241 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5242 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5243 int rc = 0;
5244 int bytes_returned = 0;
5245 __u16 params, byte_count;
5246
Joe Perchesf96637b2013-05-04 22:12:25 -05005247 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248QFSAttributeRetry:
5249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5250 (void **) &pSMBr);
5251 if (rc)
5252 return rc;
5253
5254 params = 2; /* level */
5255 pSMB->TotalDataCount = 0;
5256 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005257 /* BB find exact max SMB PDU from sess structure BB */
5258 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 pSMB->MaxSetupCount = 0;
5260 pSMB->Reserved = 0;
5261 pSMB->Flags = 0;
5262 pSMB->Timeout = 0;
5263 pSMB->Reserved2 = 0;
5264 byte_count = params + 1 /* pad */ ;
5265 pSMB->TotalParameterCount = cpu_to_le16(params);
5266 pSMB->ParameterCount = pSMB->TotalParameterCount;
5267 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005268 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269 pSMB->DataCount = 0;
5270 pSMB->DataOffset = 0;
5271 pSMB->SetupCount = 1;
5272 pSMB->Reserved3 = 0;
5273 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5274 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005275 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 pSMB->ByteCount = cpu_to_le16(byte_count);
5277
5278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5280 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005281 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 } else { /* decode response */
5283 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5284
Jeff Layton820a8032011-05-04 08:05:26 -04005285 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005286 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 rc = -EIO; /* bad smb */
5288 } else {
5289 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5290 response_data =
5291 (FILE_SYSTEM_ATTRIBUTE_INFO
5292 *) (((char *) &pSMBr->hdr.Protocol) +
5293 data_offset);
5294 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005295 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 }
5297 }
5298 cifs_buf_release(pSMB);
5299
5300 if (rc == -EAGAIN)
5301 goto QFSAttributeRetry;
5302
5303 return rc;
5304}
5305
5306int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005307CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308{
5309/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5310 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5311 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5312 FILE_SYSTEM_DEVICE_INFO *response_data;
5313 int rc = 0;
5314 int bytes_returned = 0;
5315 __u16 params, byte_count;
5316
Joe Perchesf96637b2013-05-04 22:12:25 -05005317 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318QFSDeviceRetry:
5319 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5320 (void **) &pSMBr);
5321 if (rc)
5322 return rc;
5323
5324 params = 2; /* level */
5325 pSMB->TotalDataCount = 0;
5326 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005327 /* BB find exact max SMB PDU from sess structure BB */
5328 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pSMB->MaxSetupCount = 0;
5330 pSMB->Reserved = 0;
5331 pSMB->Flags = 0;
5332 pSMB->Timeout = 0;
5333 pSMB->Reserved2 = 0;
5334 byte_count = params + 1 /* pad */ ;
5335 pSMB->TotalParameterCount = cpu_to_le16(params);
5336 pSMB->ParameterCount = pSMB->TotalParameterCount;
5337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005338 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339
5340 pSMB->DataCount = 0;
5341 pSMB->DataOffset = 0;
5342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005346 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 pSMB->ByteCount = cpu_to_le16(byte_count);
5348
5349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5351 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005352 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 } else { /* decode response */
5354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5355
Jeff Layton820a8032011-05-04 08:05:26 -04005356 if (rc || get_bcc(&pSMBr->hdr) <
5357 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 rc = -EIO; /* bad smb */
5359 else {
5360 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5361 response_data =
Steve French737b7582005-04-28 22:41:06 -07005362 (FILE_SYSTEM_DEVICE_INFO *)
5363 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 data_offset);
5365 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005366 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 }
5368 }
5369 cifs_buf_release(pSMB);
5370
5371 if (rc == -EAGAIN)
5372 goto QFSDeviceRetry;
5373
5374 return rc;
5375}
5376
5377int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005378CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379{
5380/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5381 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5382 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5383 FILE_SYSTEM_UNIX_INFO *response_data;
5384 int rc = 0;
5385 int bytes_returned = 0;
5386 __u16 params, byte_count;
5387
Joe Perchesf96637b2013-05-04 22:12:25 -05005388 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005390 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5391 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 if (rc)
5393 return rc;
5394
5395 params = 2; /* level */
5396 pSMB->TotalDataCount = 0;
5397 pSMB->DataCount = 0;
5398 pSMB->DataOffset = 0;
5399 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005400 /* BB find exact max SMB PDU from sess structure BB */
5401 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 pSMB->MaxSetupCount = 0;
5403 pSMB->Reserved = 0;
5404 pSMB->Flags = 0;
5405 pSMB->Timeout = 0;
5406 pSMB->Reserved2 = 0;
5407 byte_count = params + 1 /* pad */ ;
5408 pSMB->ParameterCount = cpu_to_le16(params);
5409 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005410 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5411 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 pSMB->SetupCount = 1;
5413 pSMB->Reserved3 = 0;
5414 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005416 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 pSMB->ByteCount = cpu_to_le16(byte_count);
5418
5419 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5420 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5421 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005422 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 } else { /* decode response */
5424 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5425
Jeff Layton820a8032011-05-04 08:05:26 -04005426 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 rc = -EIO; /* bad smb */
5428 } else {
5429 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5430 response_data =
5431 (FILE_SYSTEM_UNIX_INFO
5432 *) (((char *) &pSMBr->hdr.Protocol) +
5433 data_offset);
5434 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005435 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 }
5437 }
5438 cifs_buf_release(pSMB);
5439
5440 if (rc == -EAGAIN)
5441 goto QFSUnixRetry;
5442
5443
5444 return rc;
5445}
5446
Jeremy Allisonac670552005-06-22 17:26:35 -07005447int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005448CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005449{
5450/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5451 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5452 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5453 int rc = 0;
5454 int bytes_returned = 0;
5455 __u16 params, param_offset, offset, byte_count;
5456
Joe Perchesf96637b2013-05-04 22:12:25 -05005457 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005458SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005459 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005460 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5461 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005462 if (rc)
5463 return rc;
5464
5465 params = 4; /* 2 bytes zero followed by info level. */
5466 pSMB->MaxSetupCount = 0;
5467 pSMB->Reserved = 0;
5468 pSMB->Flags = 0;
5469 pSMB->Timeout = 0;
5470 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005471 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5472 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005473 offset = param_offset + params;
5474
5475 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005476 /* BB find exact max SMB PDU from sess structure BB */
5477 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005478 pSMB->SetupCount = 1;
5479 pSMB->Reserved3 = 0;
5480 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5481 byte_count = 1 /* pad */ + params + 12;
5482
5483 pSMB->DataCount = cpu_to_le16(12);
5484 pSMB->ParameterCount = cpu_to_le16(params);
5485 pSMB->TotalDataCount = pSMB->DataCount;
5486 pSMB->TotalParameterCount = pSMB->ParameterCount;
5487 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5488 pSMB->DataOffset = cpu_to_le16(offset);
5489
5490 /* Params. */
5491 pSMB->FileNum = 0;
5492 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5493
5494 /* Data. */
5495 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5496 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5497 pSMB->ClientUnixCap = cpu_to_le64(cap);
5498
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005499 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005500 pSMB->ByteCount = cpu_to_le16(byte_count);
5501
5502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5504 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005505 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005506 } else { /* decode response */
5507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005508 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005509 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005510 }
5511 cifs_buf_release(pSMB);
5512
5513 if (rc == -EAGAIN)
5514 goto SETFSUnixRetry;
5515
5516 return rc;
5517}
5518
5519
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520
5521int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005522CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005523 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524{
5525/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5526 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5527 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5528 FILE_SYSTEM_POSIX_INFO *response_data;
5529 int rc = 0;
5530 int bytes_returned = 0;
5531 __u16 params, byte_count;
5532
Joe Perchesf96637b2013-05-04 22:12:25 -05005533 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534QFSPosixRetry:
5535 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5536 (void **) &pSMBr);
5537 if (rc)
5538 return rc;
5539
5540 params = 2; /* level */
5541 pSMB->TotalDataCount = 0;
5542 pSMB->DataCount = 0;
5543 pSMB->DataOffset = 0;
5544 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005545 /* BB find exact max SMB PDU from sess structure BB */
5546 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 pSMB->MaxSetupCount = 0;
5548 pSMB->Reserved = 0;
5549 pSMB->Flags = 0;
5550 pSMB->Timeout = 0;
5551 pSMB->Reserved2 = 0;
5552 byte_count = params + 1 /* pad */ ;
5553 pSMB->ParameterCount = cpu_to_le16(params);
5554 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005555 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5556 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 pSMB->SetupCount = 1;
5558 pSMB->Reserved3 = 0;
5559 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5560 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005561 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 pSMB->ByteCount = cpu_to_le16(byte_count);
5563
5564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5566 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005567 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 } else { /* decode response */
5569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5570
Jeff Layton820a8032011-05-04 08:05:26 -04005571 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 rc = -EIO; /* bad smb */
5573 } else {
5574 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5575 response_data =
5576 (FILE_SYSTEM_POSIX_INFO
5577 *) (((char *) &pSMBr->hdr.Protocol) +
5578 data_offset);
5579 FSData->f_bsize =
5580 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005581 /*
5582 * much prefer larger but if server doesn't report
5583 * a valid size than 4K is a reasonable minimum
5584 */
5585 if (FSData->f_bsize < 512)
5586 FSData->f_bsize = 4096;
5587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 FSData->f_blocks =
5589 le64_to_cpu(response_data->TotalBlocks);
5590 FSData->f_bfree =
5591 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005592 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 FSData->f_bavail = FSData->f_bfree;
5594 } else {
5595 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005596 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 }
Steve French790fe572007-07-07 19:25:05 +00005598 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005600 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005601 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005603 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 }
5605 }
5606 cifs_buf_release(pSMB);
5607
5608 if (rc == -EAGAIN)
5609 goto QFSPosixRetry;
5610
5611 return rc;
5612}
5613
5614
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005615/*
5616 * We can not use write of zero bytes trick to set file size due to need for
5617 * large file support. Also note that this SetPathInfo is preferred to
5618 * SetFileInfo based method in next routine which is only needed to work around
5619 * a sharing violation bugin Samba which this routine can run into.
5620 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005622CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005623 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5624 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625{
5626 struct smb_com_transaction2_spi_req *pSMB = NULL;
5627 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5628 struct file_end_of_file_info *parm_data;
5629 int name_len;
5630 int rc = 0;
5631 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005632 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005633
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 __u16 params, byte_count, data_count, param_offset, offset;
5635
Joe Perchesf96637b2013-05-04 22:12:25 -05005636 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637SetEOFRetry:
5638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5639 (void **) &pSMBr);
5640 if (rc)
5641 return rc;
5642
5643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5644 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005645 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5646 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 name_len++; /* trailing null */
5648 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005649 } else {
5650 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 }
5652 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005653 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005655 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 pSMB->MaxSetupCount = 0;
5657 pSMB->Reserved = 0;
5658 pSMB->Flags = 0;
5659 pSMB->Timeout = 0;
5660 pSMB->Reserved2 = 0;
5661 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005662 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005664 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005665 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5666 pSMB->InformationLevel =
5667 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5668 else
5669 pSMB->InformationLevel =
5670 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5671 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5673 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005674 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 else
5676 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005677 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 }
5679
5680 parm_data =
5681 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5682 offset);
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->SetupCount = 1;
5686 pSMB->Reserved3 = 0;
5687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5688 byte_count = 3 /* pad */ + params + data_count;
5689 pSMB->DataCount = cpu_to_le16(data_count);
5690 pSMB->TotalDataCount = pSMB->DataCount;
5691 pSMB->ParameterCount = cpu_to_le16(params);
5692 pSMB->TotalParameterCount = pSMB->ParameterCount;
5693 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005694 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695 parm_data->FileSize = cpu_to_le64(size);
5696 pSMB->ByteCount = cpu_to_le16(byte_count);
5697 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5698 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005699 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005700 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701
5702 cifs_buf_release(pSMB);
5703
5704 if (rc == -EAGAIN)
5705 goto SetEOFRetry;
5706
5707 return rc;
5708}
5709
5710int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005711CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5712 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713{
5714 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 struct file_end_of_file_info *parm_data;
5716 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 __u16 params, param_offset, offset, byte_count, count;
5718
Joe Perchesf96637b2013-05-04 22:12:25 -05005719 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5720 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005721 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5722
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 if (rc)
5724 return rc;
5725
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005726 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5727 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005728
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729 params = 6;
5730 pSMB->MaxSetupCount = 0;
5731 pSMB->Reserved = 0;
5732 pSMB->Flags = 0;
5733 pSMB->Timeout = 0;
5734 pSMB->Reserved2 = 0;
5735 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5736 offset = param_offset + params;
5737
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 count = sizeof(struct file_end_of_file_info);
5739 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005740 /* BB find exact max SMB PDU from sess structure BB */
5741 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->SetupCount = 1;
5743 pSMB->Reserved3 = 0;
5744 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5745 byte_count = 3 /* pad */ + params + count;
5746 pSMB->DataCount = cpu_to_le16(count);
5747 pSMB->ParameterCount = cpu_to_le16(params);
5748 pSMB->TotalDataCount = pSMB->DataCount;
5749 pSMB->TotalParameterCount = pSMB->ParameterCount;
5750 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5751 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005752 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5753 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 pSMB->DataOffset = cpu_to_le16(offset);
5755 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005756 pSMB->Fid = cfile->fid.netfid;
5757 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5759 pSMB->InformationLevel =
5760 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5761 else
5762 pSMB->InformationLevel =
5763 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005764 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5766 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005767 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 else
5769 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005770 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 }
5772 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005773 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005775 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005776 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005778 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5779 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 }
5781
Steve French50c2f752007-07-13 00:33:32 +00005782 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783 since file handle passed in no longer valid */
5784
5785 return rc;
5786}
5787
Steve French50c2f752007-07-13 00:33:32 +00005788/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 an open handle, rather than by pathname - this is awkward due to
5790 potential access conflicts on the open, but it is unavoidable for these
5791 old servers since the only other choice is to go from 100 nanosecond DCE
5792 time and resort to the original setpathinfo level which takes the ancient
5793 DOS time format with 2 second granularity */
5794int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005795CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005796 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797{
5798 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 char *data_offset;
5800 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 __u16 params, param_offset, offset, byte_count, count;
5802
Joe Perchesf96637b2013-05-04 22:12:25 -05005803 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005804 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5805
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 if (rc)
5807 return rc;
5808
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005809 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5810 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005811
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 params = 6;
5813 pSMB->MaxSetupCount = 0;
5814 pSMB->Reserved = 0;
5815 pSMB->Flags = 0;
5816 pSMB->Timeout = 0;
5817 pSMB->Reserved2 = 0;
5818 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5819 offset = param_offset + params;
5820
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005821 data_offset = (char *)pSMB +
5822 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823
Steve French26f57362007-08-30 22:09:15 +00005824 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005826 /* BB find max SMB PDU from sess */
5827 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 pSMB->SetupCount = 1;
5829 pSMB->Reserved3 = 0;
5830 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5831 byte_count = 3 /* pad */ + params + count;
5832 pSMB->DataCount = cpu_to_le16(count);
5833 pSMB->ParameterCount = cpu_to_le16(params);
5834 pSMB->TotalDataCount = pSMB->DataCount;
5835 pSMB->TotalParameterCount = pSMB->ParameterCount;
5836 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5837 pSMB->DataOffset = cpu_to_le16(offset);
5838 pSMB->Fid = fid;
5839 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5841 else
5842 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5843 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005844 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005846 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005847 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005848 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005849 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005850 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5851 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852
Steve French50c2f752007-07-13 00:33:32 +00005853 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 since file handle passed in no longer valid */
5855
5856 return rc;
5857}
5858
Jeff Layton6d22f092008-09-23 11:48:35 -04005859int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005860CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005861 bool delete_file, __u16 fid, __u32 pid_of_opener)
5862{
5863 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5864 char *data_offset;
5865 int rc = 0;
5866 __u16 params, param_offset, offset, byte_count, count;
5867
Joe Perchesf96637b2013-05-04 22:12:25 -05005868 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005869 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5870
5871 if (rc)
5872 return rc;
5873
5874 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5875 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5876
5877 params = 6;
5878 pSMB->MaxSetupCount = 0;
5879 pSMB->Reserved = 0;
5880 pSMB->Flags = 0;
5881 pSMB->Timeout = 0;
5882 pSMB->Reserved2 = 0;
5883 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5884 offset = param_offset + params;
5885
5886 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5887
5888 count = 1;
5889 pSMB->MaxParameterCount = cpu_to_le16(2);
5890 /* BB find max SMB PDU from sess */
5891 pSMB->MaxDataCount = cpu_to_le16(1000);
5892 pSMB->SetupCount = 1;
5893 pSMB->Reserved3 = 0;
5894 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5895 byte_count = 3 /* pad */ + params + count;
5896 pSMB->DataCount = cpu_to_le16(count);
5897 pSMB->ParameterCount = cpu_to_le16(params);
5898 pSMB->TotalDataCount = pSMB->DataCount;
5899 pSMB->TotalParameterCount = pSMB->ParameterCount;
5900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5901 pSMB->DataOffset = cpu_to_le16(offset);
5902 pSMB->Fid = fid;
5903 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5904 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005905 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005906 pSMB->ByteCount = cpu_to_le16(byte_count);
5907 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005908 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005909 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005910 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005911 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005912
5913 return rc;
5914}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
5916int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005917CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005918 const char *fileName, const FILE_BASIC_INFO *data,
5919 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920{
5921 TRANSACTION2_SPI_REQ *pSMB = NULL;
5922 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5923 int name_len;
5924 int rc = 0;
5925 int bytes_returned = 0;
5926 char *data_offset;
5927 __u16 params, param_offset, offset, byte_count, count;
5928
Joe Perchesf96637b2013-05-04 22:12:25 -05005929 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930
5931SetTimesRetry:
5932 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5933 (void **) &pSMBr);
5934 if (rc)
5935 return rc;
5936
5937 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5938 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005939 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5940 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 name_len++; /* trailing null */
5942 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10005943 } else {
5944 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 }
5946
5947 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005948 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005950 /* BB find max SMB PDU from sess structure BB */
5951 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 pSMB->MaxSetupCount = 0;
5953 pSMB->Reserved = 0;
5954 pSMB->Flags = 0;
5955 pSMB->Timeout = 0;
5956 pSMB->Reserved2 = 0;
5957 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005958 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 offset = param_offset + params;
5960 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5961 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5962 pSMB->DataOffset = cpu_to_le16(offset);
5963 pSMB->SetupCount = 1;
5964 pSMB->Reserved3 = 0;
5965 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5966 byte_count = 3 /* pad */ + params + count;
5967
5968 pSMB->DataCount = cpu_to_le16(count);
5969 pSMB->ParameterCount = cpu_to_le16(params);
5970 pSMB->TotalDataCount = pSMB->DataCount;
5971 pSMB->TotalParameterCount = pSMB->ParameterCount;
5972 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5974 else
5975 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5976 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005977 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005978 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 pSMB->ByteCount = cpu_to_le16(byte_count);
5980 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5981 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005982 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005983 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984
5985 cifs_buf_release(pSMB);
5986
5987 if (rc == -EAGAIN)
5988 goto SetTimesRetry;
5989
5990 return rc;
5991}
5992
5993/* Can not be used to set time stamps yet (due to old DOS time format) */
5994/* Can be used to set attributes */
5995#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5996 handling it anyway and NT4 was what we thought it would be needed for
5997 Do not delete it until we prove whether needed for Win9x though */
5998int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005999CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 __u16 dos_attrs, const struct nls_table *nls_codepage)
6001{
6002 SETATTR_REQ *pSMB = NULL;
6003 SETATTR_RSP *pSMBr = NULL;
6004 int rc = 0;
6005 int bytes_returned;
6006 int name_len;
6007
Joe Perchesf96637b2013-05-04 22:12:25 -05006008 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
6010SetAttrLgcyRetry:
6011 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
6012 (void **) &pSMBr);
6013 if (rc)
6014 return rc;
6015
6016 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6017 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006018 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
6019 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 name_len++; /* trailing null */
6021 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006022 } else {
6023 name_len = copy_path_name(pSMB->fileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 }
6025 pSMB->attr = cpu_to_le16(dos_attrs);
6026 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006027 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 pSMB->ByteCount = cpu_to_le16(name_len + 1);
6029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006031 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006032 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033
6034 cifs_buf_release(pSMB);
6035
6036 if (rc == -EAGAIN)
6037 goto SetAttrLgcyRetry;
6038
6039 return rc;
6040}
6041#endif /* temporarily unneeded SetAttr legacy function */
6042
Jeff Layton654cf142009-07-09 20:02:49 -04006043static void
6044cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
6045 const struct cifs_unix_set_info_args *args)
6046{
Eric W. Biederman49418b22013-02-06 00:57:56 -08006047 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04006048 u64 mode = args->mode;
6049
Eric W. Biederman49418b22013-02-06 00:57:56 -08006050 if (uid_valid(args->uid))
6051 uid = from_kuid(&init_user_ns, args->uid);
6052 if (gid_valid(args->gid))
6053 gid = from_kgid(&init_user_ns, args->gid);
6054
Jeff Layton654cf142009-07-09 20:02:49 -04006055 /*
6056 * Samba server ignores set of file size to zero due to bugs in some
6057 * older clients, but we should be precise - we use SetFileSize to
6058 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006059 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04006060 * zero instead of -1 here
6061 */
6062 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
6063 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
6064 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
6065 data_offset->LastAccessTime = cpu_to_le64(args->atime);
6066 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08006067 data_offset->Uid = cpu_to_le64(uid);
6068 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04006069 /* better to leave device as zero when it is */
6070 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
6071 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
6072 data_offset->Permissions = cpu_to_le64(mode);
6073
6074 if (S_ISREG(mode))
6075 data_offset->Type = cpu_to_le32(UNIX_FILE);
6076 else if (S_ISDIR(mode))
6077 data_offset->Type = cpu_to_le32(UNIX_DIR);
6078 else if (S_ISLNK(mode))
6079 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6080 else if (S_ISCHR(mode))
6081 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6082 else if (S_ISBLK(mode))
6083 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6084 else if (S_ISFIFO(mode))
6085 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6086 else if (S_ISSOCK(mode))
6087 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6088}
6089
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006091CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006092 const struct cifs_unix_set_info_args *args,
6093 u16 fid, u32 pid_of_opener)
6094{
6095 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006096 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006097 int rc = 0;
6098 u16 params, param_offset, offset, byte_count, count;
6099
Joe Perchesf96637b2013-05-04 22:12:25 -05006100 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006101 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6102
6103 if (rc)
6104 return rc;
6105
6106 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6107 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6108
6109 params = 6;
6110 pSMB->MaxSetupCount = 0;
6111 pSMB->Reserved = 0;
6112 pSMB->Flags = 0;
6113 pSMB->Timeout = 0;
6114 pSMB->Reserved2 = 0;
6115 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6116 offset = param_offset + params;
6117
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006118 data_offset = (char *)pSMB +
6119 offsetof(struct smb_hdr, Protocol) + offset;
6120
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006121 count = sizeof(FILE_UNIX_BASIC_INFO);
6122
6123 pSMB->MaxParameterCount = cpu_to_le16(2);
6124 /* BB find max SMB PDU from sess */
6125 pSMB->MaxDataCount = cpu_to_le16(1000);
6126 pSMB->SetupCount = 1;
6127 pSMB->Reserved3 = 0;
6128 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6129 byte_count = 3 /* pad */ + params + count;
6130 pSMB->DataCount = cpu_to_le16(count);
6131 pSMB->ParameterCount = cpu_to_le16(params);
6132 pSMB->TotalDataCount = pSMB->DataCount;
6133 pSMB->TotalParameterCount = pSMB->ParameterCount;
6134 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6135 pSMB->DataOffset = cpu_to_le16(offset);
6136 pSMB->Fid = fid;
6137 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6138 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006139 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006140 pSMB->ByteCount = cpu_to_le16(byte_count);
6141
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006142 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006143
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006144 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006145 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006146 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006147 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6148 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006149
6150 /* Note: On -EAGAIN error only caller can retry on handle based calls
6151 since file handle passed in no longer valid */
6152
6153 return rc;
6154}
6155
6156int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006157CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006158 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006159 const struct cifs_unix_set_info_args *args,
6160 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161{
6162 TRANSACTION2_SPI_REQ *pSMB = NULL;
6163 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6164 int name_len;
6165 int rc = 0;
6166 int bytes_returned = 0;
6167 FILE_UNIX_BASIC_INFO *data_offset;
6168 __u16 params, param_offset, offset, count, byte_count;
6169
Joe Perchesf96637b2013-05-04 22:12:25 -05006170 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171setPermsRetry:
6172 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6173 (void **) &pSMBr);
6174 if (rc)
6175 return rc;
6176
6177 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6178 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006179 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006180 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181 name_len++; /* trailing null */
6182 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006183 } else {
6184 name_len = copy_path_name(pSMB->FileName, file_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 }
6186
6187 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006188 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006190 /* BB find max SMB PDU from sess structure BB */
6191 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192 pSMB->MaxSetupCount = 0;
6193 pSMB->Reserved = 0;
6194 pSMB->Flags = 0;
6195 pSMB->Timeout = 0;
6196 pSMB->Reserved2 = 0;
6197 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006198 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 offset = param_offset + params;
6200 data_offset =
6201 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6202 offset);
6203 memset(data_offset, 0, count);
6204 pSMB->DataOffset = cpu_to_le16(offset);
6205 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6206 pSMB->SetupCount = 1;
6207 pSMB->Reserved3 = 0;
6208 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6209 byte_count = 3 /* pad */ + params + count;
6210 pSMB->ParameterCount = cpu_to_le16(params);
6211 pSMB->DataCount = cpu_to_le16(count);
6212 pSMB->TotalParameterCount = pSMB->ParameterCount;
6213 pSMB->TotalDataCount = pSMB->DataCount;
6214 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6215 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006216 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006217
Jeff Layton654cf142009-07-09 20:02:49 -04006218 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219
6220 pSMB->ByteCount = cpu_to_le16(byte_count);
6221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006223 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006224 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225
Steve French0d817bc2008-05-22 02:02:03 +00006226 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 if (rc == -EAGAIN)
6228 goto setPermsRetry;
6229 return rc;
6230}
6231
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006233/*
6234 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6235 * function used by listxattr and getxattr type calls. When ea_name is set,
6236 * it looks for that attribute name and stuffs that value into the EAData
6237 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6238 * buffer. In both cases, the return value is either the length of the
6239 * resulting data or a negative error code. If EAData is a NULL pointer then
6240 * the data isn't copied to it, but the length is returned.
6241 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006243CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006244 const unsigned char *searchName, const unsigned char *ea_name,
6245 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006246 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247{
6248 /* BB assumes one setup word */
6249 TRANSACTION2_QPI_REQ *pSMB = NULL;
6250 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006251 int remap = cifs_remap(cifs_sb);
6252 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 int rc = 0;
6254 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006255 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006256 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006257 struct fea *temp_fea;
6258 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006259 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006261 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262
Joe Perchesf96637b2013-05-04 22:12:25 -05006263 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264QAllEAsRetry:
6265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6266 (void **) &pSMBr);
6267 if (rc)
6268 return rc;
6269
6270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006271 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006272 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6273 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006274 list_len++; /* trailing null */
6275 list_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006276 } else {
6277 list_len = copy_path_name(pSMB->FileName, searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278 }
6279
Jeff Layton6e462b92010-02-10 16:18:26 -05006280 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 pSMB->TotalDataCount = 0;
6282 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006283 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006284 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 pSMB->MaxSetupCount = 0;
6286 pSMB->Reserved = 0;
6287 pSMB->Flags = 0;
6288 pSMB->Timeout = 0;
6289 pSMB->Reserved2 = 0;
6290 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006291 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 pSMB->DataCount = 0;
6293 pSMB->DataOffset = 0;
6294 pSMB->SetupCount = 1;
6295 pSMB->Reserved3 = 0;
6296 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6297 byte_count = params + 1 /* pad */ ;
6298 pSMB->TotalParameterCount = cpu_to_le16(params);
6299 pSMB->ParameterCount = pSMB->TotalParameterCount;
6300 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6301 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006302 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 pSMB->ByteCount = cpu_to_le16(byte_count);
6304
6305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6307 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006308 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006309 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006311
6312
6313 /* BB also check enough total bytes returned */
6314 /* BB we need to improve the validity checking
6315 of these trans2 responses */
6316
6317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006318 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006319 rc = -EIO; /* bad smb */
6320 goto QAllEAsOut;
6321 }
6322
6323 /* check that length of list is not more than bcc */
6324 /* check that each entry does not go beyond length
6325 of list */
6326 /* check that each element of each entry does not
6327 go beyond end of list */
6328 /* validate_trans2_offsets() */
6329 /* BB check if start of smb + data_offset > &bcc+ bcc */
6330
6331 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6332 ea_response_data = (struct fealist *)
6333 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6334
Jeff Layton6e462b92010-02-10 16:18:26 -05006335 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006336 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006337 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006338 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006339 /* didn't find the named attribute */
6340 if (ea_name)
6341 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006342 goto QAllEAsOut;
6343 }
6344
Jeff Layton0cd126b2010-02-10 16:18:26 -05006345 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006346 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006347 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006348 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006349 rc = -EIO;
6350 goto QAllEAsOut;
6351 }
6352
Jeff Laytonf0d38682010-02-10 16:18:26 -05006353 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006354 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006355 temp_fea = ea_response_data->list;
6356 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006357 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006358 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006359 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006360
Jeff Layton6e462b92010-02-10 16:18:26 -05006361 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006362 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006363 /* make sure we can read name_len and value_len */
6364 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006365 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006366 rc = -EIO;
6367 goto QAllEAsOut;
6368 }
6369
6370 name_len = temp_fea->name_len;
6371 value_len = le16_to_cpu(temp_fea->value_len);
6372 list_len -= name_len + 1 + value_len;
6373 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006374 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006375 rc = -EIO;
6376 goto QAllEAsOut;
6377 }
6378
Jeff Layton31c05192010-02-10 16:18:26 -05006379 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006380 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006381 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006382 temp_ptr += name_len + 1;
6383 rc = value_len;
6384 if (buf_size == 0)
6385 goto QAllEAsOut;
6386 if ((size_t)value_len > buf_size) {
6387 rc = -ERANGE;
6388 goto QAllEAsOut;
6389 }
6390 memcpy(EAData, temp_ptr, value_len);
6391 goto QAllEAsOut;
6392 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006393 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006394 /* account for prefix user. and trailing null */
6395 rc += (5 + 1 + name_len);
6396 if (rc < (int) buf_size) {
6397 memcpy(EAData, "user.", 5);
6398 EAData += 5;
6399 memcpy(EAData, temp_ptr, name_len);
6400 EAData += name_len;
6401 /* null terminate name */
6402 *EAData = 0;
6403 ++EAData;
6404 } else if (buf_size == 0) {
6405 /* skip copy - calc size only */
6406 } else {
6407 /* stop before overrun buffer */
6408 rc = -ERANGE;
6409 break;
6410 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006411 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006412 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006413 temp_fea = (struct fea *)temp_ptr;
6414 }
6415
Jeff Layton31c05192010-02-10 16:18:26 -05006416 /* didn't find the named attribute */
6417 if (ea_name)
6418 rc = -ENODATA;
6419
Jeff Laytonf0d38682010-02-10 16:18:26 -05006420QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006421 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422 if (rc == -EAGAIN)
6423 goto QAllEAsRetry;
6424
6425 return (ssize_t)rc;
6426}
6427
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006429CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6430 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006431 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006432 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433{
6434 struct smb_com_transaction2_spi_req *pSMB = NULL;
6435 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6436 struct fealist *parm_data;
6437 int name_len;
6438 int rc = 0;
6439 int bytes_returned = 0;
6440 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006441 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
Joe Perchesf96637b2013-05-04 22:12:25 -05006443 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444SetEARetry:
6445 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6446 (void **) &pSMBr);
6447 if (rc)
6448 return rc;
6449
6450 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6451 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006452 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6453 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454 name_len++; /* trailing null */
6455 name_len *= 2;
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10006456 } else {
6457 name_len = copy_path_name(pSMB->FileName, fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 }
6459
6460 params = 6 + name_len;
6461
6462 /* done calculating parms using name_len of file name,
6463 now use name_len to calculate length of ea name
6464 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006465 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466 name_len = 0;
6467 else
Steve French50c2f752007-07-13 00:33:32 +00006468 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006469
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006470 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006472 /* BB find max SMB PDU from sess */
6473 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474 pSMB->MaxSetupCount = 0;
6475 pSMB->Reserved = 0;
6476 pSMB->Flags = 0;
6477 pSMB->Timeout = 0;
6478 pSMB->Reserved2 = 0;
6479 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006480 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481 offset = param_offset + params;
6482 pSMB->InformationLevel =
6483 cpu_to_le16(SMB_SET_FILE_EA);
6484
Arnd Bergmannade7db92018-02-02 16:48:47 +01006485 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6487 pSMB->DataOffset = cpu_to_le16(offset);
6488 pSMB->SetupCount = 1;
6489 pSMB->Reserved3 = 0;
6490 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6491 byte_count = 3 /* pad */ + params + count;
6492 pSMB->DataCount = cpu_to_le16(count);
6493 parm_data->list_len = cpu_to_le32(count);
6494 parm_data->list[0].EA_flags = 0;
6495 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006496 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006498 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006499 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500 parm_data->list[0].name[name_len] = 0;
6501 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6502 /* caller ensures that ea_value_len is less than 64K but
6503 we need to ensure that it fits within the smb */
6504
Steve French50c2f752007-07-13 00:33:32 +00006505 /*BB add length check to see if it would fit in
6506 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006507 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6508 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006509 memcpy(parm_data->list[0].name+name_len+1,
6510 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511
6512 pSMB->TotalDataCount = pSMB->DataCount;
6513 pSMB->ParameterCount = cpu_to_le16(params);
6514 pSMB->TotalParameterCount = pSMB->ParameterCount;
6515 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006516 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517 pSMB->ByteCount = cpu_to_le16(byte_count);
6518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6519 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006520 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006521 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522
6523 cifs_buf_release(pSMB);
6524
6525 if (rc == -EAGAIN)
6526 goto SetEARetry;
6527
6528 return rc;
6529}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530#endif