1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * fs/cifs/cifssmb.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) International Business Machines Corp., 2002,2010
5*4882a593Smuzhiyun * Author(s): Steve French (sfrench@us.ibm.com)
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Contains the routines for constructing the SMB PDUs themselves
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This library is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun * it under the terms of the GNU Lesser General Public License as published
11*4882a593Smuzhiyun * by the Free Software Foundation; either version 2.1 of the License, or
12*4882a593Smuzhiyun * (at your option) any later version.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * This library is distributed in the hope that it will be useful,
15*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17*4882a593Smuzhiyun * the GNU Lesser General Public License for more details.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * You should have received a copy of the GNU Lesser General Public License
20*4882a593Smuzhiyun * along with this library; if not, write to the Free Software
21*4882a593Smuzhiyun * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25*4882a593Smuzhiyun /* These are mostly routines that operate on a pathname, or on a tree id */
26*4882a593Smuzhiyun /* (mounted volume), but there are eight handle based routines which must be */
27*4882a593Smuzhiyun /* treated slightly differently for reconnection purposes since we never */
28*4882a593Smuzhiyun /* want to reuse a stale file handle and only the caller knows the file info */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <linux/fs.h>
31*4882a593Smuzhiyun #include <linux/kernel.h>
32*4882a593Smuzhiyun #include <linux/vfs.h>
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun #include <linux/posix_acl_xattr.h>
35*4882a593Smuzhiyun #include <linux/pagemap.h>
36*4882a593Smuzhiyun #include <linux/swap.h>
37*4882a593Smuzhiyun #include <linux/task_io_accounting_ops.h>
38*4882a593Smuzhiyun #include <linux/uaccess.h>
39*4882a593Smuzhiyun #include "cifspdu.h"
40*4882a593Smuzhiyun #include "cifsglob.h"
41*4882a593Smuzhiyun #include "cifsacl.h"
42*4882a593Smuzhiyun #include "cifsproto.h"
43*4882a593Smuzhiyun #include "cifs_unicode.h"
44*4882a593Smuzhiyun #include "cifs_debug.h"
45*4882a593Smuzhiyun #include "smb2proto.h"
46*4882a593Smuzhiyun #include "fscache.h"
47*4882a593Smuzhiyun #include "smbdirect.h"
48*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
49*4882a593Smuzhiyun #include "dfs_cache.h"
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #ifdef CONFIG_CIFS_POSIX
53*4882a593Smuzhiyun static struct {
54*4882a593Smuzhiyun int index;
55*4882a593Smuzhiyun char *name;
56*4882a593Smuzhiyun } protocols[] = {
57*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
58*4882a593Smuzhiyun {LANMAN_PROT, "\2LM1.2X002"},
59*4882a593Smuzhiyun {LANMAN2_PROT, "\2LANMAN2.1"},
60*4882a593Smuzhiyun #endif /* weak password hashing for legacy clients */
61*4882a593Smuzhiyun {CIFS_PROT, "\2NT LM 0.12"},
62*4882a593Smuzhiyun {POSIX_PROT, "\2POSIX 2"},
63*4882a593Smuzhiyun {BAD_PROT, "\2"}
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun #else
66*4882a593Smuzhiyun static struct {
67*4882a593Smuzhiyun int index;
68*4882a593Smuzhiyun char *name;
69*4882a593Smuzhiyun } protocols[] = {
70*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
71*4882a593Smuzhiyun {LANMAN_PROT, "\2LM1.2X002"},
72*4882a593Smuzhiyun {LANMAN2_PROT, "\2LANMAN2.1"},
73*4882a593Smuzhiyun #endif /* weak password hashing for legacy clients */
74*4882a593Smuzhiyun {CIFS_PROT, "\2NT LM 0.12"},
75*4882a593Smuzhiyun {BAD_PROT, "\2"}
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* define the number of elements in the cifs dialect array */
80*4882a593Smuzhiyun #ifdef CONFIG_CIFS_POSIX
81*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
82*4882a593Smuzhiyun #define CIFS_NUM_PROT 4
83*4882a593Smuzhiyun #else
84*4882a593Smuzhiyun #define CIFS_NUM_PROT 2
85*4882a593Smuzhiyun #endif /* CIFS_WEAK_PW_HASH */
86*4882a593Smuzhiyun #else /* not posix */
87*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
88*4882a593Smuzhiyun #define CIFS_NUM_PROT 3
89*4882a593Smuzhiyun #else
90*4882a593Smuzhiyun #define CIFS_NUM_PROT 1
91*4882a593Smuzhiyun #endif /* CONFIG_CIFS_WEAK_PW_HASH */
92*4882a593Smuzhiyun #endif /* CIFS_POSIX */
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * Mark as invalid, all open files on tree connections since they
96*4882a593Smuzhiyun * were closed when session to server was lost.
97*4882a593Smuzhiyun */
98*4882a593Smuzhiyun void
cifs_mark_open_files_invalid(struct cifs_tcon * tcon)99*4882a593Smuzhiyun cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct cifsFileInfo *open_file = NULL;
102*4882a593Smuzhiyun struct list_head *tmp;
103*4882a593Smuzhiyun struct list_head *tmp1;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* list all files open on tree connection and mark them invalid */
106*4882a593Smuzhiyun spin_lock(&tcon->open_file_lock);
107*4882a593Smuzhiyun list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
108*4882a593Smuzhiyun open_file = list_entry(tmp, struct cifsFileInfo, tlist);
109*4882a593Smuzhiyun open_file->invalidHandle = true;
110*4882a593Smuzhiyun open_file->oplock_break_cancelled = true;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun spin_unlock(&tcon->open_file_lock);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun mutex_lock(&tcon->crfid.fid_mutex);
115*4882a593Smuzhiyun tcon->crfid.is_valid = false;
116*4882a593Smuzhiyun /* cached handle is not valid, so SMB2_CLOSE won't be sent below */
117*4882a593Smuzhiyun close_shroot_lease_locked(&tcon->crfid);
118*4882a593Smuzhiyun memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
119*4882a593Smuzhiyun mutex_unlock(&tcon->crfid.fid_mutex);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * BB Add call to invalidate_inodes(sb) for all superblocks mounted
123*4882a593Smuzhiyun * to this tcon.
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* reconnect the socket, tcon, and smb session if needed */
128*4882a593Smuzhiyun static int
cifs_reconnect_tcon(struct cifs_tcon * tcon,int smb_command)129*4882a593Smuzhiyun cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun int rc;
132*4882a593Smuzhiyun struct cifs_ses *ses;
133*4882a593Smuzhiyun struct TCP_Server_Info *server;
134*4882a593Smuzhiyun struct nls_table *nls_codepage;
135*4882a593Smuzhiyun int retries;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /*
138*4882a593Smuzhiyun * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
139*4882a593Smuzhiyun * tcp and smb session status done differently for those three - in the
140*4882a593Smuzhiyun * calling routine
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun if (!tcon)
143*4882a593Smuzhiyun return 0;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun ses = tcon->ses;
146*4882a593Smuzhiyun server = ses->server;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun * only tree disconnect, open, and write, (and ulogoff which does not
150*4882a593Smuzhiyun * have tcon) are allowed as we start force umount
151*4882a593Smuzhiyun */
152*4882a593Smuzhiyun if (tcon->tidStatus == CifsExiting) {
153*4882a593Smuzhiyun if (smb_command != SMB_COM_WRITE_ANDX &&
154*4882a593Smuzhiyun smb_command != SMB_COM_OPEN_ANDX &&
155*4882a593Smuzhiyun smb_command != SMB_COM_TREE_DISCONNECT) {
156*4882a593Smuzhiyun cifs_dbg(FYI, "can not send cmd %d while umounting\n",
157*4882a593Smuzhiyun smb_command);
158*4882a593Smuzhiyun return -ENODEV;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun retries = server->nr_targets;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /*
165*4882a593Smuzhiyun * Give demultiplex thread up to 10 seconds to each target available for
166*4882a593Smuzhiyun * reconnect -- should be greater than cifs socket timeout which is 7
167*4882a593Smuzhiyun * seconds.
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun while (server->tcpStatus == CifsNeedReconnect) {
170*4882a593Smuzhiyun rc = wait_event_interruptible_timeout(server->response_q,
171*4882a593Smuzhiyun (server->tcpStatus != CifsNeedReconnect),
172*4882a593Smuzhiyun 10 * HZ);
173*4882a593Smuzhiyun if (rc < 0) {
174*4882a593Smuzhiyun cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
175*4882a593Smuzhiyun __func__);
176*4882a593Smuzhiyun return -ERESTARTSYS;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* are we still trying to reconnect? */
180*4882a593Smuzhiyun if (server->tcpStatus != CifsNeedReconnect)
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (retries && --retries)
184*4882a593Smuzhiyun continue;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /*
187*4882a593Smuzhiyun * on "soft" mounts we wait once. Hard mounts keep
188*4882a593Smuzhiyun * retrying until process is killed or server comes
189*4882a593Smuzhiyun * back on-line
190*4882a593Smuzhiyun */
191*4882a593Smuzhiyun if (!tcon->retry) {
192*4882a593Smuzhiyun cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
193*4882a593Smuzhiyun return -EHOSTDOWN;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun retries = server->nr_targets;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (!ses->need_reconnect && !tcon->need_reconnect)
199*4882a593Smuzhiyun return 0;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun nls_codepage = load_nls_default();
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * need to prevent multiple threads trying to simultaneously
205*4882a593Smuzhiyun * reconnect the same SMB session
206*4882a593Smuzhiyun */
207*4882a593Smuzhiyun mutex_lock(&ses->session_mutex);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /*
210*4882a593Smuzhiyun * Recheck after acquire mutex. If another thread is negotiating
211*4882a593Smuzhiyun * and the server never sends an answer the socket will be closed
212*4882a593Smuzhiyun * and tcpStatus set to reconnect.
213*4882a593Smuzhiyun */
214*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedReconnect) {
215*4882a593Smuzhiyun rc = -EHOSTDOWN;
216*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
217*4882a593Smuzhiyun goto out;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun rc = cifs_negotiate_protocol(0, ses);
221*4882a593Smuzhiyun if (rc == 0 && ses->need_reconnect)
222*4882a593Smuzhiyun rc = cifs_setup_session(0, ses, nls_codepage);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* do we need to reconnect tcon? */
225*4882a593Smuzhiyun if (rc || !tcon->need_reconnect) {
226*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
227*4882a593Smuzhiyun goto out;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun cifs_mark_open_files_invalid(tcon);
231*4882a593Smuzhiyun rc = cifs_tree_connect(0, tcon, nls_codepage);
232*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
233*4882a593Smuzhiyun cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun if (rc) {
236*4882a593Smuzhiyun pr_warn_once("reconnect tcon failed rc = %d\n", rc);
237*4882a593Smuzhiyun goto out;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun atomic_inc(&tconInfoReconnectCount);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* tell server Unix caps we support */
243*4882a593Smuzhiyun if (cap_unix(ses))
244*4882a593Smuzhiyun reset_cifs_unix_caps(0, tcon, NULL, NULL);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * Removed call to reopen open files here. It is safer (and faster) to
248*4882a593Smuzhiyun * reopen files one at a time as needed in read and write.
249*4882a593Smuzhiyun *
250*4882a593Smuzhiyun * FIXME: what about file locks? don't we need to reclaim them ASAP?
251*4882a593Smuzhiyun */
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun out:
254*4882a593Smuzhiyun /*
255*4882a593Smuzhiyun * Check if handle based operation so we know whether we can continue
256*4882a593Smuzhiyun * or not without returning to caller to reset file handle
257*4882a593Smuzhiyun */
258*4882a593Smuzhiyun switch (smb_command) {
259*4882a593Smuzhiyun case SMB_COM_READ_ANDX:
260*4882a593Smuzhiyun case SMB_COM_WRITE_ANDX:
261*4882a593Smuzhiyun case SMB_COM_CLOSE:
262*4882a593Smuzhiyun case SMB_COM_FIND_CLOSE2:
263*4882a593Smuzhiyun case SMB_COM_LOCKING_ANDX:
264*4882a593Smuzhiyun rc = -EAGAIN;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun unload_nls(nls_codepage);
268*4882a593Smuzhiyun return rc;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Allocate and return pointer to an SMB request buffer, and set basic
272*4882a593Smuzhiyun SMB information in the SMB header. If the return code is zero, this
273*4882a593Smuzhiyun function must have filled in request_buf pointer */
274*4882a593Smuzhiyun static int
small_smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf)275*4882a593Smuzhiyun small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
276*4882a593Smuzhiyun void **request_buf)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun int rc;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun rc = cifs_reconnect_tcon(tcon, smb_command);
281*4882a593Smuzhiyun if (rc)
282*4882a593Smuzhiyun return rc;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun *request_buf = cifs_small_buf_get();
285*4882a593Smuzhiyun if (*request_buf == NULL) {
286*4882a593Smuzhiyun /* BB should we add a retry in here if not a writepage? */
287*4882a593Smuzhiyun return -ENOMEM;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun header_assemble((struct smb_hdr *) *request_buf, smb_command,
291*4882a593Smuzhiyun tcon, wct);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (tcon != NULL)
294*4882a593Smuzhiyun cifs_stats_inc(&tcon->num_smbs_sent);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun return 0;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun int
small_smb_init_no_tc(const int smb_command,const int wct,struct cifs_ses * ses,void ** request_buf)300*4882a593Smuzhiyun small_smb_init_no_tc(const int smb_command, const int wct,
301*4882a593Smuzhiyun struct cifs_ses *ses, void **request_buf)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun int rc;
304*4882a593Smuzhiyun struct smb_hdr *buffer;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun rc = small_smb_init(smb_command, wct, NULL, request_buf);
307*4882a593Smuzhiyun if (rc)
308*4882a593Smuzhiyun return rc;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun buffer = (struct smb_hdr *)*request_buf;
311*4882a593Smuzhiyun buffer->Mid = get_next_mid(ses->server);
312*4882a593Smuzhiyun if (ses->capabilities & CAP_UNICODE)
313*4882a593Smuzhiyun buffer->Flags2 |= SMBFLG2_UNICODE;
314*4882a593Smuzhiyun if (ses->capabilities & CAP_STATUS32)
315*4882a593Smuzhiyun buffer->Flags2 |= SMBFLG2_ERR_STATUS;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* uid, tid can stay at zero as set in header assemble */
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* BB add support for turning on the signing when
320*4882a593Smuzhiyun this function is used after 1st of session setup requests */
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun return rc;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /* If the return code is zero, this function must fill in request_buf pointer */
326*4882a593Smuzhiyun static int
__smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)327*4882a593Smuzhiyun __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
328*4882a593Smuzhiyun void **request_buf, void **response_buf)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun *request_buf = cifs_buf_get();
331*4882a593Smuzhiyun if (*request_buf == NULL) {
332*4882a593Smuzhiyun /* BB should we add a retry in here if not a writepage? */
333*4882a593Smuzhiyun return -ENOMEM;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun /* Although the original thought was we needed the response buf for */
336*4882a593Smuzhiyun /* potential retries of smb operations it turns out we can determine */
337*4882a593Smuzhiyun /* from the mid flags when the request buffer can be resent without */
338*4882a593Smuzhiyun /* having to use a second distinct buffer for the response */
339*4882a593Smuzhiyun if (response_buf)
340*4882a593Smuzhiyun *response_buf = *request_buf;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
343*4882a593Smuzhiyun wct);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (tcon != NULL)
346*4882a593Smuzhiyun cifs_stats_inc(&tcon->num_smbs_sent);
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun return 0;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /* If the return code is zero, this function must fill in request_buf pointer */
352*4882a593Smuzhiyun static int
smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)353*4882a593Smuzhiyun smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
354*4882a593Smuzhiyun void **request_buf, void **response_buf)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun int rc;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun rc = cifs_reconnect_tcon(tcon, smb_command);
359*4882a593Smuzhiyun if (rc)
360*4882a593Smuzhiyun return rc;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun static int
smb_init_no_reconnect(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)366*4882a593Smuzhiyun smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
367*4882a593Smuzhiyun void **request_buf, void **response_buf)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun if (tcon->ses->need_reconnect || tcon->need_reconnect)
370*4882a593Smuzhiyun return -EHOSTDOWN;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
validate_t2(struct smb_t2_rsp * pSMB)375*4882a593Smuzhiyun static int validate_t2(struct smb_t2_rsp *pSMB)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun unsigned int total_size;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* check for plausible wct */
380*4882a593Smuzhiyun if (pSMB->hdr.WordCount < 10)
381*4882a593Smuzhiyun goto vt2_err;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* check for parm and data offset going beyond end of smb */
384*4882a593Smuzhiyun if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
385*4882a593Smuzhiyun get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
386*4882a593Smuzhiyun goto vt2_err;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
389*4882a593Smuzhiyun if (total_size >= 512)
390*4882a593Smuzhiyun goto vt2_err;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* check that bcc is at least as big as parms + data, and that it is
393*4882a593Smuzhiyun * less than negotiated smb buffer
394*4882a593Smuzhiyun */
395*4882a593Smuzhiyun total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
396*4882a593Smuzhiyun if (total_size > get_bcc(&pSMB->hdr) ||
397*4882a593Smuzhiyun total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
398*4882a593Smuzhiyun goto vt2_err;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return 0;
401*4882a593Smuzhiyun vt2_err:
402*4882a593Smuzhiyun cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
403*4882a593Smuzhiyun sizeof(struct smb_t2_rsp) + 16);
404*4882a593Smuzhiyun return -EINVAL;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun static int
decode_ext_sec_blob(struct cifs_ses * ses,NEGOTIATE_RSP * pSMBr)408*4882a593Smuzhiyun decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun int rc = 0;
411*4882a593Smuzhiyun u16 count;
412*4882a593Smuzhiyun char *guid = pSMBr->u.extended_response.GUID;
413*4882a593Smuzhiyun struct TCP_Server_Info *server = ses->server;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun count = get_bcc(&pSMBr->hdr);
416*4882a593Smuzhiyun if (count < SMB1_CLIENT_GUID_SIZE)
417*4882a593Smuzhiyun return -EIO;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
420*4882a593Smuzhiyun if (server->srv_count > 1) {
421*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
422*4882a593Smuzhiyun if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
423*4882a593Smuzhiyun cifs_dbg(FYI, "server UID changed\n");
424*4882a593Smuzhiyun memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun } else {
427*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
428*4882a593Smuzhiyun memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (count == SMB1_CLIENT_GUID_SIZE) {
432*4882a593Smuzhiyun server->sec_ntlmssp = true;
433*4882a593Smuzhiyun } else {
434*4882a593Smuzhiyun count -= SMB1_CLIENT_GUID_SIZE;
435*4882a593Smuzhiyun rc = decode_negTokenInit(
436*4882a593Smuzhiyun pSMBr->u.extended_response.SecurityBlob, count, server);
437*4882a593Smuzhiyun if (rc != 1)
438*4882a593Smuzhiyun return -EINVAL;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun int
cifs_enable_signing(struct TCP_Server_Info * server,bool mnt_sign_required)445*4882a593Smuzhiyun cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun bool srv_sign_required = server->sec_mode & server->vals->signing_required;
448*4882a593Smuzhiyun bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
449*4882a593Smuzhiyun bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /*
452*4882a593Smuzhiyun * Is signing required by mnt options? If not then check
453*4882a593Smuzhiyun * global_secflags to see if it is there.
454*4882a593Smuzhiyun */
455*4882a593Smuzhiyun if (!mnt_sign_required)
456*4882a593Smuzhiyun mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
457*4882a593Smuzhiyun CIFSSEC_MUST_SIGN);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /*
460*4882a593Smuzhiyun * If signing is required then it's automatically enabled too,
461*4882a593Smuzhiyun * otherwise, check to see if the secflags allow it.
462*4882a593Smuzhiyun */
463*4882a593Smuzhiyun mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
464*4882a593Smuzhiyun (global_secflags & CIFSSEC_MAY_SIGN);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* If server requires signing, does client allow it? */
467*4882a593Smuzhiyun if (srv_sign_required) {
468*4882a593Smuzhiyun if (!mnt_sign_enabled) {
469*4882a593Smuzhiyun cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!\n");
470*4882a593Smuzhiyun return -ENOTSUPP;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun server->sign = true;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* If client requires signing, does server allow it? */
476*4882a593Smuzhiyun if (mnt_sign_required) {
477*4882a593Smuzhiyun if (!srv_sign_enabled) {
478*4882a593Smuzhiyun cifs_dbg(VFS, "Server does not support signing!\n");
479*4882a593Smuzhiyun return -ENOTSUPP;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun server->sign = true;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun if (cifs_rdma_enabled(server) && server->sign)
485*4882a593Smuzhiyun cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled\n");
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
491*4882a593Smuzhiyun static int
decode_lanman_negprot_rsp(struct TCP_Server_Info * server,NEGOTIATE_RSP * pSMBr)492*4882a593Smuzhiyun decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun __s16 tmp;
495*4882a593Smuzhiyun struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
498*4882a593Smuzhiyun return -EOPNOTSUPP;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun server->sec_mode = le16_to_cpu(rsp->SecurityMode);
501*4882a593Smuzhiyun server->maxReq = min_t(unsigned int,
502*4882a593Smuzhiyun le16_to_cpu(rsp->MaxMpxCount),
503*4882a593Smuzhiyun cifs_max_pending);
504*4882a593Smuzhiyun set_credits(server, server->maxReq);
505*4882a593Smuzhiyun server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
506*4882a593Smuzhiyun /* set up max_read for readpages check */
507*4882a593Smuzhiyun server->max_read = server->maxBuf;
508*4882a593Smuzhiyun /* even though we do not use raw we might as well set this
509*4882a593Smuzhiyun accurately, in case we ever find a need for it */
510*4882a593Smuzhiyun if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
511*4882a593Smuzhiyun server->max_rw = 0xFF00;
512*4882a593Smuzhiyun server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
513*4882a593Smuzhiyun } else {
514*4882a593Smuzhiyun server->max_rw = 0;/* do not need to use raw anyway */
515*4882a593Smuzhiyun server->capabilities = CAP_MPX_MODE;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
518*4882a593Smuzhiyun if (tmp == -1) {
519*4882a593Smuzhiyun /* OS/2 often does not set timezone therefore
520*4882a593Smuzhiyun * we must use server time to calc time zone.
521*4882a593Smuzhiyun * Could deviate slightly from the right zone.
522*4882a593Smuzhiyun * Smallest defined timezone difference is 15 minutes
523*4882a593Smuzhiyun * (i.e. Nepal). Rounding up/down is done to match
524*4882a593Smuzhiyun * this requirement.
525*4882a593Smuzhiyun */
526*4882a593Smuzhiyun int val, seconds, remain, result;
527*4882a593Smuzhiyun struct timespec64 ts;
528*4882a593Smuzhiyun time64_t utc = ktime_get_real_seconds();
529*4882a593Smuzhiyun ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
530*4882a593Smuzhiyun rsp->SrvTime.Time, 0);
531*4882a593Smuzhiyun cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
532*4882a593Smuzhiyun ts.tv_sec, utc,
533*4882a593Smuzhiyun utc - ts.tv_sec);
534*4882a593Smuzhiyun val = (int)(utc - ts.tv_sec);
535*4882a593Smuzhiyun seconds = abs(val);
536*4882a593Smuzhiyun result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
537*4882a593Smuzhiyun remain = seconds % MIN_TZ_ADJ;
538*4882a593Smuzhiyun if (remain >= (MIN_TZ_ADJ / 2))
539*4882a593Smuzhiyun result += MIN_TZ_ADJ;
540*4882a593Smuzhiyun if (val < 0)
541*4882a593Smuzhiyun result = -result;
542*4882a593Smuzhiyun server->timeAdj = result;
543*4882a593Smuzhiyun } else {
544*4882a593Smuzhiyun server->timeAdj = (int)tmp;
545*4882a593Smuzhiyun server->timeAdj *= 60; /* also in seconds */
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /* BB get server time for time conversions and add
551*4882a593Smuzhiyun code to use it and timezone since this is not UTC */
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (rsp->EncryptionKeyLength ==
554*4882a593Smuzhiyun cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
555*4882a593Smuzhiyun memcpy(server->cryptkey, rsp->EncryptionKey,
556*4882a593Smuzhiyun CIFS_CRYPTO_KEY_SIZE);
557*4882a593Smuzhiyun } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
558*4882a593Smuzhiyun return -EIO; /* need cryptkey unless plain text */
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun cifs_dbg(FYI, "LANMAN negotiated\n");
562*4882a593Smuzhiyun return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun #else
565*4882a593Smuzhiyun static inline int
decode_lanman_negprot_rsp(struct TCP_Server_Info * server,NEGOTIATE_RSP * pSMBr)566*4882a593Smuzhiyun decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
569*4882a593Smuzhiyun return -EOPNOTSUPP;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun #endif
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun static bool
should_set_ext_sec_flag(enum securityEnum sectype)574*4882a593Smuzhiyun should_set_ext_sec_flag(enum securityEnum sectype)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun switch (sectype) {
577*4882a593Smuzhiyun case RawNTLMSSP:
578*4882a593Smuzhiyun case Kerberos:
579*4882a593Smuzhiyun return true;
580*4882a593Smuzhiyun case Unspecified:
581*4882a593Smuzhiyun if (global_secflags &
582*4882a593Smuzhiyun (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
583*4882a593Smuzhiyun return true;
584*4882a593Smuzhiyun fallthrough;
585*4882a593Smuzhiyun default:
586*4882a593Smuzhiyun return false;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun int
CIFSSMBNegotiate(const unsigned int xid,struct cifs_ses * ses)591*4882a593Smuzhiyun CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun NEGOTIATE_REQ *pSMB;
594*4882a593Smuzhiyun NEGOTIATE_RSP *pSMBr;
595*4882a593Smuzhiyun int rc = 0;
596*4882a593Smuzhiyun int bytes_returned;
597*4882a593Smuzhiyun int i;
598*4882a593Smuzhiyun struct TCP_Server_Info *server = ses->server;
599*4882a593Smuzhiyun u16 count;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun if (!server) {
602*4882a593Smuzhiyun WARN(1, "%s: server is NULL!\n", __func__);
603*4882a593Smuzhiyun return -EIO;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
607*4882a593Smuzhiyun (void **) &pSMB, (void **) &pSMBr);
608*4882a593Smuzhiyun if (rc)
609*4882a593Smuzhiyun return rc;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun pSMB->hdr.Mid = get_next_mid(server);
612*4882a593Smuzhiyun pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun if (should_set_ext_sec_flag(ses->sectype)) {
615*4882a593Smuzhiyun cifs_dbg(FYI, "Requesting extended security\n");
616*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun count = 0;
620*4882a593Smuzhiyun /*
621*4882a593Smuzhiyun * We know that all the name entries in the protocols array
622*4882a593Smuzhiyun * are short (< 16 bytes anyway) and are NUL terminated.
623*4882a593Smuzhiyun */
624*4882a593Smuzhiyun for (i = 0; i < CIFS_NUM_PROT; i++) {
625*4882a593Smuzhiyun size_t len = strlen(protocols[i].name) + 1;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
628*4882a593Smuzhiyun count += len;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
631*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
634*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
635*4882a593Smuzhiyun if (rc != 0)
636*4882a593Smuzhiyun goto neg_err_exit;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun server->dialect = le16_to_cpu(pSMBr->DialectIndex);
639*4882a593Smuzhiyun cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
640*4882a593Smuzhiyun /* Check wct = 1 error case */
641*4882a593Smuzhiyun if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
642*4882a593Smuzhiyun /* core returns wct = 1, but we do not ask for core - otherwise
643*4882a593Smuzhiyun small wct just comes when dialect index is -1 indicating we
644*4882a593Smuzhiyun could not negotiate a common dialect */
645*4882a593Smuzhiyun rc = -EOPNOTSUPP;
646*4882a593Smuzhiyun goto neg_err_exit;
647*4882a593Smuzhiyun } else if (pSMBr->hdr.WordCount == 13) {
648*4882a593Smuzhiyun server->negflavor = CIFS_NEGFLAVOR_LANMAN;
649*4882a593Smuzhiyun rc = decode_lanman_negprot_rsp(server, pSMBr);
650*4882a593Smuzhiyun goto signing_check;
651*4882a593Smuzhiyun } else if (pSMBr->hdr.WordCount != 17) {
652*4882a593Smuzhiyun /* unknown wct */
653*4882a593Smuzhiyun rc = -EOPNOTSUPP;
654*4882a593Smuzhiyun goto neg_err_exit;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun /* else wct == 17, NTLM or better */
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun server->sec_mode = pSMBr->SecurityMode;
659*4882a593Smuzhiyun if ((server->sec_mode & SECMODE_USER) == 0)
660*4882a593Smuzhiyun cifs_dbg(FYI, "share mode security\n");
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun /* one byte, so no need to convert this or EncryptionKeyLen from
663*4882a593Smuzhiyun little endian */
664*4882a593Smuzhiyun server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
665*4882a593Smuzhiyun cifs_max_pending);
666*4882a593Smuzhiyun set_credits(server, server->maxReq);
667*4882a593Smuzhiyun /* probably no need to store and check maxvcs */
668*4882a593Smuzhiyun server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
669*4882a593Smuzhiyun /* set up max_read for readpages check */
670*4882a593Smuzhiyun server->max_read = server->maxBuf;
671*4882a593Smuzhiyun server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
672*4882a593Smuzhiyun cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
673*4882a593Smuzhiyun server->capabilities = le32_to_cpu(pSMBr->Capabilities);
674*4882a593Smuzhiyun server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
675*4882a593Smuzhiyun server->timeAdj *= 60;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
678*4882a593Smuzhiyun server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
679*4882a593Smuzhiyun memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
680*4882a593Smuzhiyun CIFS_CRYPTO_KEY_SIZE);
681*4882a593Smuzhiyun } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
682*4882a593Smuzhiyun server->capabilities & CAP_EXTENDED_SECURITY) {
683*4882a593Smuzhiyun server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
684*4882a593Smuzhiyun rc = decode_ext_sec_blob(ses, pSMBr);
685*4882a593Smuzhiyun } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
686*4882a593Smuzhiyun rc = -EIO; /* no crypt key only if plain text pwd */
687*4882a593Smuzhiyun } else {
688*4882a593Smuzhiyun server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
689*4882a593Smuzhiyun server->capabilities &= ~CAP_EXTENDED_SECURITY;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun signing_check:
693*4882a593Smuzhiyun if (!rc)
694*4882a593Smuzhiyun rc = cifs_enable_signing(server, ses->sign);
695*4882a593Smuzhiyun neg_err_exit:
696*4882a593Smuzhiyun cifs_buf_release(pSMB);
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun cifs_dbg(FYI, "negprot rc %d\n", rc);
699*4882a593Smuzhiyun return rc;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun int
CIFSSMBTDis(const unsigned int xid,struct cifs_tcon * tcon)703*4882a593Smuzhiyun CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun struct smb_hdr *smb_buffer;
706*4882a593Smuzhiyun int rc = 0;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun cifs_dbg(FYI, "In tree disconnect\n");
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun /* BB: do we need to check this? These should never be NULL. */
711*4882a593Smuzhiyun if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
712*4882a593Smuzhiyun return -EIO;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /*
715*4882a593Smuzhiyun * No need to return error on this operation if tid invalidated and
716*4882a593Smuzhiyun * closed on server already e.g. due to tcp session crashing. Also,
717*4882a593Smuzhiyun * the tcon is no longer on the list, so no need to take lock before
718*4882a593Smuzhiyun * checking this.
719*4882a593Smuzhiyun */
720*4882a593Smuzhiyun if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
721*4882a593Smuzhiyun return 0;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
724*4882a593Smuzhiyun (void **)&smb_buffer);
725*4882a593Smuzhiyun if (rc)
726*4882a593Smuzhiyun return rc;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
729*4882a593Smuzhiyun cifs_small_buf_release(smb_buffer);
730*4882a593Smuzhiyun if (rc)
731*4882a593Smuzhiyun cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun /* No need to return error on this operation if tid invalidated and
734*4882a593Smuzhiyun closed on server already e.g. due to tcp session crashing */
735*4882a593Smuzhiyun if (rc == -EAGAIN)
736*4882a593Smuzhiyun rc = 0;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun return rc;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /*
742*4882a593Smuzhiyun * This is a no-op for now. We're not really interested in the reply, but
743*4882a593Smuzhiyun * rather in the fact that the server sent one and that server->lstrp
744*4882a593Smuzhiyun * gets updated.
745*4882a593Smuzhiyun *
746*4882a593Smuzhiyun * FIXME: maybe we should consider checking that the reply matches request?
747*4882a593Smuzhiyun */
748*4882a593Smuzhiyun static void
cifs_echo_callback(struct mid_q_entry * mid)749*4882a593Smuzhiyun cifs_echo_callback(struct mid_q_entry *mid)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun struct TCP_Server_Info *server = mid->callback_data;
752*4882a593Smuzhiyun struct cifs_credits credits = { .value = 1, .instance = 0 };
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun DeleteMidQEntry(mid);
755*4882a593Smuzhiyun add_credits(server, &credits, CIFS_ECHO_OP);
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun int
CIFSSMBEcho(struct TCP_Server_Info * server)759*4882a593Smuzhiyun CIFSSMBEcho(struct TCP_Server_Info *server)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun ECHO_REQ *smb;
762*4882a593Smuzhiyun int rc = 0;
763*4882a593Smuzhiyun struct kvec iov[2];
764*4882a593Smuzhiyun struct smb_rqst rqst = { .rq_iov = iov,
765*4882a593Smuzhiyun .rq_nvec = 2 };
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun cifs_dbg(FYI, "In echo request\n");
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
770*4882a593Smuzhiyun if (rc)
771*4882a593Smuzhiyun return rc;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun if (server->capabilities & CAP_UNICODE)
774*4882a593Smuzhiyun smb->hdr.Flags2 |= SMBFLG2_UNICODE;
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /* set up echo request */
777*4882a593Smuzhiyun smb->hdr.Tid = 0xffff;
778*4882a593Smuzhiyun smb->hdr.WordCount = 1;
779*4882a593Smuzhiyun put_unaligned_le16(1, &smb->EchoCount);
780*4882a593Smuzhiyun put_bcc(1, &smb->hdr);
781*4882a593Smuzhiyun smb->Data[0] = 'a';
782*4882a593Smuzhiyun inc_rfc1001_len(smb, 3);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun iov[0].iov_len = 4;
785*4882a593Smuzhiyun iov[0].iov_base = smb;
786*4882a593Smuzhiyun iov[1].iov_len = get_rfc1002_length(smb);
787*4882a593Smuzhiyun iov[1].iov_base = (char *)smb + 4;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
790*4882a593Smuzhiyun server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
791*4882a593Smuzhiyun if (rc)
792*4882a593Smuzhiyun cifs_dbg(FYI, "Echo request failed: %d\n", rc);
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun cifs_small_buf_release(smb);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun return rc;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun int
CIFSSMBLogoff(const unsigned int xid,struct cifs_ses * ses)800*4882a593Smuzhiyun CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun LOGOFF_ANDX_REQ *pSMB;
803*4882a593Smuzhiyun int rc = 0;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun /*
808*4882a593Smuzhiyun * BB: do we need to check validity of ses and server? They should
809*4882a593Smuzhiyun * always be valid since we have an active reference. If not, that
810*4882a593Smuzhiyun * should probably be a BUG()
811*4882a593Smuzhiyun */
812*4882a593Smuzhiyun if (!ses || !ses->server)
813*4882a593Smuzhiyun return -EIO;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun mutex_lock(&ses->session_mutex);
816*4882a593Smuzhiyun if (ses->need_reconnect)
817*4882a593Smuzhiyun goto session_already_dead; /* no need to send SMBlogoff if uid
818*4882a593Smuzhiyun already closed due to reconnect */
819*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
820*4882a593Smuzhiyun if (rc) {
821*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
822*4882a593Smuzhiyun return rc;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun pSMB->hdr.Mid = get_next_mid(ses->server);
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (ses->server->sign)
828*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun pSMB->hdr.Uid = ses->Suid;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF;
833*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
834*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
835*4882a593Smuzhiyun session_already_dead:
836*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun /* if session dead then we do not need to do ulogoff,
839*4882a593Smuzhiyun since server closed smb session, no sense reporting
840*4882a593Smuzhiyun error */
841*4882a593Smuzhiyun if (rc == -EAGAIN)
842*4882a593Smuzhiyun rc = 0;
843*4882a593Smuzhiyun return rc;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun int
CIFSPOSIXDelFile(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,__u16 type,const struct nls_table * nls_codepage,int remap)847*4882a593Smuzhiyun CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
848*4882a593Smuzhiyun const char *fileName, __u16 type,
849*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
852*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
853*4882a593Smuzhiyun struct unlink_psx_rq *pRqD;
854*4882a593Smuzhiyun int name_len;
855*4882a593Smuzhiyun int rc = 0;
856*4882a593Smuzhiyun int bytes_returned = 0;
857*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun cifs_dbg(FYI, "In POSIX delete\n");
860*4882a593Smuzhiyun PsxDelete:
861*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
862*4882a593Smuzhiyun (void **) &pSMBr);
863*4882a593Smuzhiyun if (rc)
864*4882a593Smuzhiyun return rc;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
867*4882a593Smuzhiyun name_len =
868*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
869*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
870*4882a593Smuzhiyun name_len++; /* trailing null */
871*4882a593Smuzhiyun name_len *= 2;
872*4882a593Smuzhiyun } else {
873*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, fileName);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun params = 6 + name_len;
877*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
878*4882a593Smuzhiyun pSMB->MaxDataCount = 0; /* BB double check this with jra */
879*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
880*4882a593Smuzhiyun pSMB->Reserved = 0;
881*4882a593Smuzhiyun pSMB->Flags = 0;
882*4882a593Smuzhiyun pSMB->Timeout = 0;
883*4882a593Smuzhiyun pSMB->Reserved2 = 0;
884*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
885*4882a593Smuzhiyun InformationLevel) - 4;
886*4882a593Smuzhiyun offset = param_offset + params;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun /* Setup pointer to Request Data (inode type) */
889*4882a593Smuzhiyun pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
890*4882a593Smuzhiyun pRqD->type = cpu_to_le16(type);
891*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
892*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
893*4882a593Smuzhiyun pSMB->SetupCount = 1;
894*4882a593Smuzhiyun pSMB->Reserved3 = 0;
895*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
896*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
899*4882a593Smuzhiyun pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
900*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
901*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
902*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
903*4882a593Smuzhiyun pSMB->Reserved4 = 0;
904*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
905*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
906*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
908*4882a593Smuzhiyun if (rc)
909*4882a593Smuzhiyun cifs_dbg(FYI, "Posix delete returned %d\n", rc);
910*4882a593Smuzhiyun cifs_buf_release(pSMB);
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun if (rc == -EAGAIN)
915*4882a593Smuzhiyun goto PsxDelete;
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun return rc;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun int
CIFSSMBDelFile(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)921*4882a593Smuzhiyun CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
922*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun DELETE_FILE_REQ *pSMB = NULL;
925*4882a593Smuzhiyun DELETE_FILE_RSP *pSMBr = NULL;
926*4882a593Smuzhiyun int rc = 0;
927*4882a593Smuzhiyun int bytes_returned;
928*4882a593Smuzhiyun int name_len;
929*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun DelFileRetry:
932*4882a593Smuzhiyun rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
933*4882a593Smuzhiyun (void **) &pSMBr);
934*4882a593Smuzhiyun if (rc)
935*4882a593Smuzhiyun return rc;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
938*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
939*4882a593Smuzhiyun PATH_MAX, cifs_sb->local_nls,
940*4882a593Smuzhiyun remap);
941*4882a593Smuzhiyun name_len++; /* trailing null */
942*4882a593Smuzhiyun name_len *= 2;
943*4882a593Smuzhiyun } else {
944*4882a593Smuzhiyun name_len = copy_path_name(pSMB->fileName, name);
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun pSMB->SearchAttributes =
947*4882a593Smuzhiyun cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
948*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
949*4882a593Smuzhiyun inc_rfc1001_len(pSMB, name_len + 1);
950*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(name_len + 1);
951*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
952*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
953*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
954*4882a593Smuzhiyun if (rc)
955*4882a593Smuzhiyun cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun cifs_buf_release(pSMB);
958*4882a593Smuzhiyun if (rc == -EAGAIN)
959*4882a593Smuzhiyun goto DelFileRetry;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun return rc;
962*4882a593Smuzhiyun }
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun int
CIFSSMBRmDir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)965*4882a593Smuzhiyun CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
966*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun DELETE_DIRECTORY_REQ *pSMB = NULL;
969*4882a593Smuzhiyun DELETE_DIRECTORY_RSP *pSMBr = NULL;
970*4882a593Smuzhiyun int rc = 0;
971*4882a593Smuzhiyun int bytes_returned;
972*4882a593Smuzhiyun int name_len;
973*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBRmDir\n");
976*4882a593Smuzhiyun RmDirRetry:
977*4882a593Smuzhiyun rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
978*4882a593Smuzhiyun (void **) &pSMBr);
979*4882a593Smuzhiyun if (rc)
980*4882a593Smuzhiyun return rc;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
983*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
984*4882a593Smuzhiyun PATH_MAX, cifs_sb->local_nls,
985*4882a593Smuzhiyun remap);
986*4882a593Smuzhiyun name_len++; /* trailing null */
987*4882a593Smuzhiyun name_len *= 2;
988*4882a593Smuzhiyun } else {
989*4882a593Smuzhiyun name_len = copy_path_name(pSMB->DirName, name);
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
993*4882a593Smuzhiyun inc_rfc1001_len(pSMB, name_len + 1);
994*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(name_len + 1);
995*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
997*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
998*4882a593Smuzhiyun if (rc)
999*4882a593Smuzhiyun cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun cifs_buf_release(pSMB);
1002*4882a593Smuzhiyun if (rc == -EAGAIN)
1003*4882a593Smuzhiyun goto RmDirRetry;
1004*4882a593Smuzhiyun return rc;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun int
CIFSSMBMkDir(const unsigned int xid,struct inode * inode,umode_t mode,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)1008*4882a593Smuzhiyun CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
1009*4882a593Smuzhiyun struct cifs_tcon *tcon, const char *name,
1010*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun int rc = 0;
1013*4882a593Smuzhiyun CREATE_DIRECTORY_REQ *pSMB = NULL;
1014*4882a593Smuzhiyun CREATE_DIRECTORY_RSP *pSMBr = NULL;
1015*4882a593Smuzhiyun int bytes_returned;
1016*4882a593Smuzhiyun int name_len;
1017*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBMkDir\n");
1020*4882a593Smuzhiyun MkDirRetry:
1021*4882a593Smuzhiyun rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1022*4882a593Smuzhiyun (void **) &pSMBr);
1023*4882a593Smuzhiyun if (rc)
1024*4882a593Smuzhiyun return rc;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1027*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1028*4882a593Smuzhiyun PATH_MAX, cifs_sb->local_nls,
1029*4882a593Smuzhiyun remap);
1030*4882a593Smuzhiyun name_len++; /* trailing null */
1031*4882a593Smuzhiyun name_len *= 2;
1032*4882a593Smuzhiyun } else {
1033*4882a593Smuzhiyun name_len = copy_path_name(pSMB->DirName, name);
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
1037*4882a593Smuzhiyun inc_rfc1001_len(pSMB, name_len + 1);
1038*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(name_len + 1);
1039*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1040*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1041*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
1042*4882a593Smuzhiyun if (rc)
1043*4882a593Smuzhiyun cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun cifs_buf_release(pSMB);
1046*4882a593Smuzhiyun if (rc == -EAGAIN)
1047*4882a593Smuzhiyun goto MkDirRetry;
1048*4882a593Smuzhiyun return rc;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun int
CIFSPOSIXCreate(const unsigned int xid,struct cifs_tcon * tcon,__u32 posix_flags,__u64 mode,__u16 * netfid,FILE_UNIX_BASIC_INFO * pRetData,__u32 * pOplock,const char * name,const struct nls_table * nls_codepage,int remap)1052*4882a593Smuzhiyun CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1053*4882a593Smuzhiyun __u32 posix_flags, __u64 mode, __u16 *netfid,
1054*4882a593Smuzhiyun FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1055*4882a593Smuzhiyun const char *name, const struct nls_table *nls_codepage,
1056*4882a593Smuzhiyun int remap)
1057*4882a593Smuzhiyun {
1058*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
1059*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
1060*4882a593Smuzhiyun int name_len;
1061*4882a593Smuzhiyun int rc = 0;
1062*4882a593Smuzhiyun int bytes_returned = 0;
1063*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
1064*4882a593Smuzhiyun OPEN_PSX_REQ *pdata;
1065*4882a593Smuzhiyun OPEN_PSX_RSP *psx_rsp;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun cifs_dbg(FYI, "In POSIX Create\n");
1068*4882a593Smuzhiyun PsxCreat:
1069*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1070*4882a593Smuzhiyun (void **) &pSMBr);
1071*4882a593Smuzhiyun if (rc)
1072*4882a593Smuzhiyun return rc;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1075*4882a593Smuzhiyun name_len =
1076*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1077*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
1078*4882a593Smuzhiyun name_len++; /* trailing null */
1079*4882a593Smuzhiyun name_len *= 2;
1080*4882a593Smuzhiyun } else {
1081*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, name);
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun params = 6 + name_len;
1085*4882a593Smuzhiyun count = sizeof(OPEN_PSX_REQ);
1086*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
1087*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1088*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
1089*4882a593Smuzhiyun pSMB->Reserved = 0;
1090*4882a593Smuzhiyun pSMB->Flags = 0;
1091*4882a593Smuzhiyun pSMB->Timeout = 0;
1092*4882a593Smuzhiyun pSMB->Reserved2 = 0;
1093*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
1094*4882a593Smuzhiyun InformationLevel) - 4;
1095*4882a593Smuzhiyun offset = param_offset + params;
1096*4882a593Smuzhiyun pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1097*4882a593Smuzhiyun pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1098*4882a593Smuzhiyun pdata->Permissions = cpu_to_le64(mode);
1099*4882a593Smuzhiyun pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1100*4882a593Smuzhiyun pdata->OpenFlags = cpu_to_le32(*pOplock);
1101*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
1102*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
1103*4882a593Smuzhiyun pSMB->SetupCount = 1;
1104*4882a593Smuzhiyun pSMB->Reserved3 = 0;
1105*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1106*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
1109*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
1110*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
1111*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
1112*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1113*4882a593Smuzhiyun pSMB->Reserved4 = 0;
1114*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
1115*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
1116*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1117*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1118*4882a593Smuzhiyun if (rc) {
1119*4882a593Smuzhiyun cifs_dbg(FYI, "Posix create returned %d\n", rc);
1120*4882a593Smuzhiyun goto psx_create_err;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun cifs_dbg(FYI, "copying inode info\n");
1124*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1127*4882a593Smuzhiyun rc = -EIO; /* bad smb */
1128*4882a593Smuzhiyun goto psx_create_err;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun /* copy return information to pRetData */
1132*4882a593Smuzhiyun psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1133*4882a593Smuzhiyun + le16_to_cpu(pSMBr->t2.DataOffset));
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1136*4882a593Smuzhiyun if (netfid)
1137*4882a593Smuzhiyun *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1138*4882a593Smuzhiyun /* Let caller know file was created so we can set the mode. */
1139*4882a593Smuzhiyun /* Do we care about the CreateAction in any other cases? */
1140*4882a593Smuzhiyun if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1141*4882a593Smuzhiyun *pOplock |= CIFS_CREATE_ACTION;
1142*4882a593Smuzhiyun /* check to make sure response data is there */
1143*4882a593Smuzhiyun if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1144*4882a593Smuzhiyun pRetData->Type = cpu_to_le32(-1); /* unknown */
1145*4882a593Smuzhiyun cifs_dbg(NOISY, "unknown type\n");
1146*4882a593Smuzhiyun } else {
1147*4882a593Smuzhiyun if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1148*4882a593Smuzhiyun + sizeof(FILE_UNIX_BASIC_INFO)) {
1149*4882a593Smuzhiyun cifs_dbg(VFS, "Open response data too small\n");
1150*4882a593Smuzhiyun pRetData->Type = cpu_to_le32(-1);
1151*4882a593Smuzhiyun goto psx_create_err;
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun memcpy((char *) pRetData,
1154*4882a593Smuzhiyun (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1155*4882a593Smuzhiyun sizeof(FILE_UNIX_BASIC_INFO));
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun psx_create_err:
1159*4882a593Smuzhiyun cifs_buf_release(pSMB);
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun if (posix_flags & SMB_O_DIRECTORY)
1162*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
1163*4882a593Smuzhiyun else
1164*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun if (rc == -EAGAIN)
1167*4882a593Smuzhiyun goto PsxCreat;
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun return rc;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun
convert_disposition(int disposition)1172*4882a593Smuzhiyun static __u16 convert_disposition(int disposition)
1173*4882a593Smuzhiyun {
1174*4882a593Smuzhiyun __u16 ofun = 0;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun switch (disposition) {
1177*4882a593Smuzhiyun case FILE_SUPERSEDE:
1178*4882a593Smuzhiyun ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1179*4882a593Smuzhiyun break;
1180*4882a593Smuzhiyun case FILE_OPEN:
1181*4882a593Smuzhiyun ofun = SMBOPEN_OAPPEND;
1182*4882a593Smuzhiyun break;
1183*4882a593Smuzhiyun case FILE_CREATE:
1184*4882a593Smuzhiyun ofun = SMBOPEN_OCREATE;
1185*4882a593Smuzhiyun break;
1186*4882a593Smuzhiyun case FILE_OPEN_IF:
1187*4882a593Smuzhiyun ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1188*4882a593Smuzhiyun break;
1189*4882a593Smuzhiyun case FILE_OVERWRITE:
1190*4882a593Smuzhiyun ofun = SMBOPEN_OTRUNC;
1191*4882a593Smuzhiyun break;
1192*4882a593Smuzhiyun case FILE_OVERWRITE_IF:
1193*4882a593Smuzhiyun ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1194*4882a593Smuzhiyun break;
1195*4882a593Smuzhiyun default:
1196*4882a593Smuzhiyun cifs_dbg(FYI, "unknown disposition %d\n", disposition);
1197*4882a593Smuzhiyun ofun = SMBOPEN_OAPPEND; /* regular open */
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun return ofun;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun static int
access_flags_to_smbopen_mode(const int access_flags)1203*4882a593Smuzhiyun access_flags_to_smbopen_mode(const int access_flags)
1204*4882a593Smuzhiyun {
1205*4882a593Smuzhiyun int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun if (masked_flags == GENERIC_READ)
1208*4882a593Smuzhiyun return SMBOPEN_READ;
1209*4882a593Smuzhiyun else if (masked_flags == GENERIC_WRITE)
1210*4882a593Smuzhiyun return SMBOPEN_WRITE;
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun /* just go for read/write */
1213*4882a593Smuzhiyun return SMBOPEN_READWRITE;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun int
SMBLegacyOpen(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const int openDisposition,const int access_flags,const int create_options,__u16 * netfid,int * pOplock,FILE_ALL_INFO * pfile_info,const struct nls_table * nls_codepage,int remap)1217*4882a593Smuzhiyun SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
1218*4882a593Smuzhiyun const char *fileName, const int openDisposition,
1219*4882a593Smuzhiyun const int access_flags, const int create_options, __u16 *netfid,
1220*4882a593Smuzhiyun int *pOplock, FILE_ALL_INFO *pfile_info,
1221*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun int rc = -EACCES;
1224*4882a593Smuzhiyun OPENX_REQ *pSMB = NULL;
1225*4882a593Smuzhiyun OPENX_RSP *pSMBr = NULL;
1226*4882a593Smuzhiyun int bytes_returned;
1227*4882a593Smuzhiyun int name_len;
1228*4882a593Smuzhiyun __u16 count;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun OldOpenRetry:
1231*4882a593Smuzhiyun rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1232*4882a593Smuzhiyun (void **) &pSMBr);
1233*4882a593Smuzhiyun if (rc)
1234*4882a593Smuzhiyun return rc;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1239*4882a593Smuzhiyun count = 1; /* account for one byte pad to word boundary */
1240*4882a593Smuzhiyun name_len =
1241*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1242*4882a593Smuzhiyun fileName, PATH_MAX, nls_codepage, remap);
1243*4882a593Smuzhiyun name_len++; /* trailing null */
1244*4882a593Smuzhiyun name_len *= 2;
1245*4882a593Smuzhiyun } else {
1246*4882a593Smuzhiyun count = 0; /* no pad */
1247*4882a593Smuzhiyun name_len = copy_path_name(pSMB->fileName, fileName);
1248*4882a593Smuzhiyun }
1249*4882a593Smuzhiyun if (*pOplock & REQ_OPLOCK)
1250*4882a593Smuzhiyun pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1251*4882a593Smuzhiyun else if (*pOplock & REQ_BATCHOPLOCK)
1252*4882a593Smuzhiyun pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1255*4882a593Smuzhiyun pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1256*4882a593Smuzhiyun pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1257*4882a593Smuzhiyun /* set file as system file if special file such
1258*4882a593Smuzhiyun as fifo and server expecting SFU style and
1259*4882a593Smuzhiyun no Unix extensions */
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun if (create_options & CREATE_OPTION_SPECIAL)
1262*4882a593Smuzhiyun pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1263*4882a593Smuzhiyun else /* BB FIXME BB */
1264*4882a593Smuzhiyun pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun if (create_options & CREATE_OPTION_READONLY)
1267*4882a593Smuzhiyun pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun /* BB FIXME BB */
1270*4882a593Smuzhiyun /* pSMB->CreateOptions = cpu_to_le32(create_options &
1271*4882a593Smuzhiyun CREATE_OPTIONS_MASK); */
1272*4882a593Smuzhiyun /* BB FIXME END BB */
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1275*4882a593Smuzhiyun pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1276*4882a593Smuzhiyun count += name_len;
1277*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
1280*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1281*4882a593Smuzhiyun (struct smb_hdr *)pSMBr, &bytes_returned, 0);
1282*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1283*4882a593Smuzhiyun if (rc) {
1284*4882a593Smuzhiyun cifs_dbg(FYI, "Error in Open = %d\n", rc);
1285*4882a593Smuzhiyun } else {
1286*4882a593Smuzhiyun /* BB verify if wct == 15 */
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun *netfid = pSMBr->Fid; /* cifs fid stays in le */
1291*4882a593Smuzhiyun /* Let caller know file was created so we can set the mode. */
1292*4882a593Smuzhiyun /* Do we care about the CreateAction in any other cases? */
1293*4882a593Smuzhiyun /* BB FIXME BB */
1294*4882a593Smuzhiyun /* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1295*4882a593Smuzhiyun *pOplock |= CIFS_CREATE_ACTION; */
1296*4882a593Smuzhiyun /* BB FIXME END */
1297*4882a593Smuzhiyun
1298*4882a593Smuzhiyun if (pfile_info) {
1299*4882a593Smuzhiyun pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1300*4882a593Smuzhiyun pfile_info->LastAccessTime = 0; /* BB fixme */
1301*4882a593Smuzhiyun pfile_info->LastWriteTime = 0; /* BB fixme */
1302*4882a593Smuzhiyun pfile_info->ChangeTime = 0; /* BB fixme */
1303*4882a593Smuzhiyun pfile_info->Attributes =
1304*4882a593Smuzhiyun cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1305*4882a593Smuzhiyun /* the file_info buf is endian converted by caller */
1306*4882a593Smuzhiyun pfile_info->AllocationSize =
1307*4882a593Smuzhiyun cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1308*4882a593Smuzhiyun pfile_info->EndOfFile = pfile_info->AllocationSize;
1309*4882a593Smuzhiyun pfile_info->NumberOfLinks = cpu_to_le32(1);
1310*4882a593Smuzhiyun pfile_info->DeletePending = 0;
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun
1314*4882a593Smuzhiyun cifs_buf_release(pSMB);
1315*4882a593Smuzhiyun if (rc == -EAGAIN)
1316*4882a593Smuzhiyun goto OldOpenRetry;
1317*4882a593Smuzhiyun return rc;
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun int
CIFS_open(const unsigned int xid,struct cifs_open_parms * oparms,int * oplock,FILE_ALL_INFO * buf)1321*4882a593Smuzhiyun CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1322*4882a593Smuzhiyun FILE_ALL_INFO *buf)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun int rc;
1325*4882a593Smuzhiyun OPEN_REQ *req = NULL;
1326*4882a593Smuzhiyun OPEN_RSP *rsp = NULL;
1327*4882a593Smuzhiyun int bytes_returned;
1328*4882a593Smuzhiyun int name_len;
1329*4882a593Smuzhiyun __u16 count;
1330*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1331*4882a593Smuzhiyun struct cifs_tcon *tcon = oparms->tcon;
1332*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
1333*4882a593Smuzhiyun const struct nls_table *nls = cifs_sb->local_nls;
1334*4882a593Smuzhiyun int create_options = oparms->create_options;
1335*4882a593Smuzhiyun int desired_access = oparms->desired_access;
1336*4882a593Smuzhiyun int disposition = oparms->disposition;
1337*4882a593Smuzhiyun const char *path = oparms->path;
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun openRetry:
1340*4882a593Smuzhiyun rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1341*4882a593Smuzhiyun (void **)&rsp);
1342*4882a593Smuzhiyun if (rc)
1343*4882a593Smuzhiyun return rc;
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun /* no commands go after this */
1346*4882a593Smuzhiyun req->AndXCommand = 0xFF;
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1349*4882a593Smuzhiyun /* account for one byte pad to word boundary */
1350*4882a593Smuzhiyun count = 1;
1351*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1352*4882a593Smuzhiyun path, PATH_MAX, nls, remap);
1353*4882a593Smuzhiyun /* trailing null */
1354*4882a593Smuzhiyun name_len++;
1355*4882a593Smuzhiyun name_len *= 2;
1356*4882a593Smuzhiyun req->NameLength = cpu_to_le16(name_len);
1357*4882a593Smuzhiyun } else {
1358*4882a593Smuzhiyun /* BB improve check for buffer overruns BB */
1359*4882a593Smuzhiyun /* no pad */
1360*4882a593Smuzhiyun count = 0;
1361*4882a593Smuzhiyun name_len = copy_path_name(req->fileName, path);
1362*4882a593Smuzhiyun req->NameLength = cpu_to_le16(name_len);
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun if (*oplock & REQ_OPLOCK)
1366*4882a593Smuzhiyun req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1367*4882a593Smuzhiyun else if (*oplock & REQ_BATCHOPLOCK)
1368*4882a593Smuzhiyun req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun req->DesiredAccess = cpu_to_le32(desired_access);
1371*4882a593Smuzhiyun req->AllocationSize = 0;
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun /*
1374*4882a593Smuzhiyun * Set file as system file if special file such as fifo and server
1375*4882a593Smuzhiyun * expecting SFU style and no Unix extensions.
1376*4882a593Smuzhiyun */
1377*4882a593Smuzhiyun if (create_options & CREATE_OPTION_SPECIAL)
1378*4882a593Smuzhiyun req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1379*4882a593Smuzhiyun else
1380*4882a593Smuzhiyun req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun /*
1383*4882a593Smuzhiyun * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1384*4882a593Smuzhiyun * sensitive checks for other servers such as Samba.
1385*4882a593Smuzhiyun */
1386*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_UNIX)
1387*4882a593Smuzhiyun req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun if (create_options & CREATE_OPTION_READONLY)
1390*4882a593Smuzhiyun req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1393*4882a593Smuzhiyun req->CreateDisposition = cpu_to_le32(disposition);
1394*4882a593Smuzhiyun req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun /* BB Expirement with various impersonation levels and verify */
1397*4882a593Smuzhiyun req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1398*4882a593Smuzhiyun req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun count += name_len;
1401*4882a593Smuzhiyun inc_rfc1001_len(req, count);
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun req->ByteCount = cpu_to_le16(count);
1404*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1405*4882a593Smuzhiyun (struct smb_hdr *)rsp, &bytes_returned, 0);
1406*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1407*4882a593Smuzhiyun if (rc) {
1408*4882a593Smuzhiyun cifs_dbg(FYI, "Error in Open = %d\n", rc);
1409*4882a593Smuzhiyun cifs_buf_release(req);
1410*4882a593Smuzhiyun if (rc == -EAGAIN)
1411*4882a593Smuzhiyun goto openRetry;
1412*4882a593Smuzhiyun return rc;
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun /* 1 byte no need to le_to_cpu */
1416*4882a593Smuzhiyun *oplock = rsp->OplockLevel;
1417*4882a593Smuzhiyun /* cifs fid stays in le */
1418*4882a593Smuzhiyun oparms->fid->netfid = rsp->Fid;
1419*4882a593Smuzhiyun oparms->fid->access = desired_access;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun /* Let caller know file was created so we can set the mode. */
1422*4882a593Smuzhiyun /* Do we care about the CreateAction in any other cases? */
1423*4882a593Smuzhiyun if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1424*4882a593Smuzhiyun *oplock |= CIFS_CREATE_ACTION;
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun if (buf) {
1427*4882a593Smuzhiyun /* copy from CreationTime to Attributes */
1428*4882a593Smuzhiyun memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1429*4882a593Smuzhiyun /* the file_info buf is endian converted by caller */
1430*4882a593Smuzhiyun buf->AllocationSize = rsp->AllocationSize;
1431*4882a593Smuzhiyun buf->EndOfFile = rsp->EndOfFile;
1432*4882a593Smuzhiyun buf->NumberOfLinks = cpu_to_le32(1);
1433*4882a593Smuzhiyun buf->DeletePending = 0;
1434*4882a593Smuzhiyun }
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun cifs_buf_release(req);
1437*4882a593Smuzhiyun return rc;
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun
1440*4882a593Smuzhiyun /*
1441*4882a593Smuzhiyun * Discard any remaining data in the current SMB. To do this, we borrow the
1442*4882a593Smuzhiyun * current bigbuf.
1443*4882a593Smuzhiyun */
1444*4882a593Smuzhiyun int
cifs_discard_remaining_data(struct TCP_Server_Info * server)1445*4882a593Smuzhiyun cifs_discard_remaining_data(struct TCP_Server_Info *server)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun unsigned int rfclen = server->pdu_size;
1448*4882a593Smuzhiyun int remaining = rfclen + server->vals->header_preamble_size -
1449*4882a593Smuzhiyun server->total_read;
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun while (remaining > 0) {
1452*4882a593Smuzhiyun int length;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun length = cifs_discard_from_socket(server,
1455*4882a593Smuzhiyun min_t(size_t, remaining,
1456*4882a593Smuzhiyun CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
1457*4882a593Smuzhiyun if (length < 0)
1458*4882a593Smuzhiyun return length;
1459*4882a593Smuzhiyun server->total_read += length;
1460*4882a593Smuzhiyun remaining -= length;
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun return 0;
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun
1466*4882a593Smuzhiyun static int
__cifs_readv_discard(struct TCP_Server_Info * server,struct mid_q_entry * mid,bool malformed)1467*4882a593Smuzhiyun __cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1468*4882a593Smuzhiyun bool malformed)
1469*4882a593Smuzhiyun {
1470*4882a593Smuzhiyun int length;
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun length = cifs_discard_remaining_data(server);
1473*4882a593Smuzhiyun dequeue_mid(mid, malformed);
1474*4882a593Smuzhiyun mid->resp_buf = server->smallbuf;
1475*4882a593Smuzhiyun server->smallbuf = NULL;
1476*4882a593Smuzhiyun return length;
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun
1479*4882a593Smuzhiyun static int
cifs_readv_discard(struct TCP_Server_Info * server,struct mid_q_entry * mid)1480*4882a593Smuzhiyun cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1481*4882a593Smuzhiyun {
1482*4882a593Smuzhiyun struct cifs_readdata *rdata = mid->callback_data;
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun return __cifs_readv_discard(server, mid, rdata->result);
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun int
cifs_readv_receive(struct TCP_Server_Info * server,struct mid_q_entry * mid)1488*4882a593Smuzhiyun cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun int length, len;
1491*4882a593Smuzhiyun unsigned int data_offset, data_len;
1492*4882a593Smuzhiyun struct cifs_readdata *rdata = mid->callback_data;
1493*4882a593Smuzhiyun char *buf = server->smallbuf;
1494*4882a593Smuzhiyun unsigned int buflen = server->pdu_size +
1495*4882a593Smuzhiyun server->vals->header_preamble_size;
1496*4882a593Smuzhiyun bool use_rdma_mr = false;
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1499*4882a593Smuzhiyun __func__, mid->mid, rdata->offset, rdata->bytes);
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun /*
1502*4882a593Smuzhiyun * read the rest of READ_RSP header (sans Data array), or whatever we
1503*4882a593Smuzhiyun * can if there's not enough data. At this point, we've read down to
1504*4882a593Smuzhiyun * the Mid.
1505*4882a593Smuzhiyun */
1506*4882a593Smuzhiyun len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
1507*4882a593Smuzhiyun HEADER_SIZE(server) + 1;
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun length = cifs_read_from_socket(server,
1510*4882a593Smuzhiyun buf + HEADER_SIZE(server) - 1, len);
1511*4882a593Smuzhiyun if (length < 0)
1512*4882a593Smuzhiyun return length;
1513*4882a593Smuzhiyun server->total_read += length;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun if (server->ops->is_session_expired &&
1516*4882a593Smuzhiyun server->ops->is_session_expired(buf)) {
1517*4882a593Smuzhiyun cifs_reconnect(server);
1518*4882a593Smuzhiyun return -1;
1519*4882a593Smuzhiyun }
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun if (server->ops->is_status_pending &&
1522*4882a593Smuzhiyun server->ops->is_status_pending(buf, server)) {
1523*4882a593Smuzhiyun cifs_discard_remaining_data(server);
1524*4882a593Smuzhiyun return -1;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun /* set up first two iov for signature check and to get credits */
1528*4882a593Smuzhiyun rdata->iov[0].iov_base = buf;
1529*4882a593Smuzhiyun rdata->iov[0].iov_len = server->vals->header_preamble_size;
1530*4882a593Smuzhiyun rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1531*4882a593Smuzhiyun rdata->iov[1].iov_len =
1532*4882a593Smuzhiyun server->total_read - server->vals->header_preamble_size;
1533*4882a593Smuzhiyun cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1534*4882a593Smuzhiyun rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1535*4882a593Smuzhiyun cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1536*4882a593Smuzhiyun rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun /* Was the SMB read successful? */
1539*4882a593Smuzhiyun rdata->result = server->ops->map_error(buf, false);
1540*4882a593Smuzhiyun if (rdata->result != 0) {
1541*4882a593Smuzhiyun cifs_dbg(FYI, "%s: server returned error %d\n",
1542*4882a593Smuzhiyun __func__, rdata->result);
1543*4882a593Smuzhiyun /* normal error on read response */
1544*4882a593Smuzhiyun return __cifs_readv_discard(server, mid, false);
1545*4882a593Smuzhiyun }
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun /* Is there enough to get to the rest of the READ_RSP header? */
1548*4882a593Smuzhiyun if (server->total_read < server->vals->read_rsp_size) {
1549*4882a593Smuzhiyun cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1550*4882a593Smuzhiyun __func__, server->total_read,
1551*4882a593Smuzhiyun server->vals->read_rsp_size);
1552*4882a593Smuzhiyun rdata->result = -EIO;
1553*4882a593Smuzhiyun return cifs_readv_discard(server, mid);
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun
1556*4882a593Smuzhiyun data_offset = server->ops->read_data_offset(buf) +
1557*4882a593Smuzhiyun server->vals->header_preamble_size;
1558*4882a593Smuzhiyun if (data_offset < server->total_read) {
1559*4882a593Smuzhiyun /*
1560*4882a593Smuzhiyun * win2k8 sometimes sends an offset of 0 when the read
1561*4882a593Smuzhiyun * is beyond the EOF. Treat it as if the data starts just after
1562*4882a593Smuzhiyun * the header.
1563*4882a593Smuzhiyun */
1564*4882a593Smuzhiyun cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1565*4882a593Smuzhiyun __func__, data_offset);
1566*4882a593Smuzhiyun data_offset = server->total_read;
1567*4882a593Smuzhiyun } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1568*4882a593Smuzhiyun /* data_offset is beyond the end of smallbuf */
1569*4882a593Smuzhiyun cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1570*4882a593Smuzhiyun __func__, data_offset);
1571*4882a593Smuzhiyun rdata->result = -EIO;
1572*4882a593Smuzhiyun return cifs_readv_discard(server, mid);
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1576*4882a593Smuzhiyun __func__, server->total_read, data_offset);
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun len = data_offset - server->total_read;
1579*4882a593Smuzhiyun if (len > 0) {
1580*4882a593Smuzhiyun /* read any junk before data into the rest of smallbuf */
1581*4882a593Smuzhiyun length = cifs_read_from_socket(server,
1582*4882a593Smuzhiyun buf + server->total_read, len);
1583*4882a593Smuzhiyun if (length < 0)
1584*4882a593Smuzhiyun return length;
1585*4882a593Smuzhiyun server->total_read += length;
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun
1588*4882a593Smuzhiyun /* how much data is in the response? */
1589*4882a593Smuzhiyun #ifdef CONFIG_CIFS_SMB_DIRECT
1590*4882a593Smuzhiyun use_rdma_mr = rdata->mr;
1591*4882a593Smuzhiyun #endif
1592*4882a593Smuzhiyun data_len = server->ops->read_data_length(buf, use_rdma_mr);
1593*4882a593Smuzhiyun if (!use_rdma_mr && (data_offset + data_len > buflen)) {
1594*4882a593Smuzhiyun /* data_len is corrupt -- discard frame */
1595*4882a593Smuzhiyun rdata->result = -EIO;
1596*4882a593Smuzhiyun return cifs_readv_discard(server, mid);
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun length = rdata->read_into_pages(server, rdata, data_len);
1600*4882a593Smuzhiyun if (length < 0)
1601*4882a593Smuzhiyun return length;
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun server->total_read += length;
1604*4882a593Smuzhiyun
1605*4882a593Smuzhiyun cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1606*4882a593Smuzhiyun server->total_read, buflen, data_len);
1607*4882a593Smuzhiyun
1608*4882a593Smuzhiyun /* discard anything left over */
1609*4882a593Smuzhiyun if (server->total_read < buflen)
1610*4882a593Smuzhiyun return cifs_readv_discard(server, mid);
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun dequeue_mid(mid, false);
1613*4882a593Smuzhiyun mid->resp_buf = server->smallbuf;
1614*4882a593Smuzhiyun server->smallbuf = NULL;
1615*4882a593Smuzhiyun return length;
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun static void
cifs_readv_callback(struct mid_q_entry * mid)1619*4882a593Smuzhiyun cifs_readv_callback(struct mid_q_entry *mid)
1620*4882a593Smuzhiyun {
1621*4882a593Smuzhiyun struct cifs_readdata *rdata = mid->callback_data;
1622*4882a593Smuzhiyun struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1623*4882a593Smuzhiyun struct TCP_Server_Info *server = tcon->ses->server;
1624*4882a593Smuzhiyun struct smb_rqst rqst = { .rq_iov = rdata->iov,
1625*4882a593Smuzhiyun .rq_nvec = 2,
1626*4882a593Smuzhiyun .rq_pages = rdata->pages,
1627*4882a593Smuzhiyun .rq_offset = rdata->page_offset,
1628*4882a593Smuzhiyun .rq_npages = rdata->nr_pages,
1629*4882a593Smuzhiyun .rq_pagesz = rdata->pagesz,
1630*4882a593Smuzhiyun .rq_tailsz = rdata->tailsz };
1631*4882a593Smuzhiyun struct cifs_credits credits = { .value = 1, .instance = 0 };
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1634*4882a593Smuzhiyun __func__, mid->mid, mid->mid_state, rdata->result,
1635*4882a593Smuzhiyun rdata->bytes);
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun switch (mid->mid_state) {
1638*4882a593Smuzhiyun case MID_RESPONSE_RECEIVED:
1639*4882a593Smuzhiyun /* result already set, check signature */
1640*4882a593Smuzhiyun if (server->sign) {
1641*4882a593Smuzhiyun int rc = 0;
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun rc = cifs_verify_signature(&rqst, server,
1644*4882a593Smuzhiyun mid->sequence_number);
1645*4882a593Smuzhiyun if (rc)
1646*4882a593Smuzhiyun cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1647*4882a593Smuzhiyun rc);
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun /* FIXME: should this be counted toward the initiating task? */
1650*4882a593Smuzhiyun task_io_account_read(rdata->got_bytes);
1651*4882a593Smuzhiyun cifs_stats_bytes_read(tcon, rdata->got_bytes);
1652*4882a593Smuzhiyun break;
1653*4882a593Smuzhiyun case MID_REQUEST_SUBMITTED:
1654*4882a593Smuzhiyun case MID_RETRY_NEEDED:
1655*4882a593Smuzhiyun rdata->result = -EAGAIN;
1656*4882a593Smuzhiyun if (server->sign && rdata->got_bytes)
1657*4882a593Smuzhiyun /* reset bytes number since we can not check a sign */
1658*4882a593Smuzhiyun rdata->got_bytes = 0;
1659*4882a593Smuzhiyun /* FIXME: should this be counted toward the initiating task? */
1660*4882a593Smuzhiyun task_io_account_read(rdata->got_bytes);
1661*4882a593Smuzhiyun cifs_stats_bytes_read(tcon, rdata->got_bytes);
1662*4882a593Smuzhiyun break;
1663*4882a593Smuzhiyun default:
1664*4882a593Smuzhiyun rdata->result = -EIO;
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun queue_work(cifsiod_wq, &rdata->work);
1668*4882a593Smuzhiyun DeleteMidQEntry(mid);
1669*4882a593Smuzhiyun add_credits(server, &credits, 0);
1670*4882a593Smuzhiyun }
1671*4882a593Smuzhiyun
1672*4882a593Smuzhiyun /* cifs_async_readv - send an async write, and set up mid to handle result */
1673*4882a593Smuzhiyun int
cifs_async_readv(struct cifs_readdata * rdata)1674*4882a593Smuzhiyun cifs_async_readv(struct cifs_readdata *rdata)
1675*4882a593Smuzhiyun {
1676*4882a593Smuzhiyun int rc;
1677*4882a593Smuzhiyun READ_REQ *smb = NULL;
1678*4882a593Smuzhiyun int wct;
1679*4882a593Smuzhiyun struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1680*4882a593Smuzhiyun struct smb_rqst rqst = { .rq_iov = rdata->iov,
1681*4882a593Smuzhiyun .rq_nvec = 2 };
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1684*4882a593Smuzhiyun __func__, rdata->offset, rdata->bytes);
1685*4882a593Smuzhiyun
1686*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_FILES)
1687*4882a593Smuzhiyun wct = 12;
1688*4882a593Smuzhiyun else {
1689*4882a593Smuzhiyun wct = 10; /* old style read */
1690*4882a593Smuzhiyun if ((rdata->offset >> 32) > 0) {
1691*4882a593Smuzhiyun /* can not handle this big offset for old */
1692*4882a593Smuzhiyun return -EIO;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun }
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1697*4882a593Smuzhiyun if (rc)
1698*4882a593Smuzhiyun return rc;
1699*4882a593Smuzhiyun
1700*4882a593Smuzhiyun smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1701*4882a593Smuzhiyun smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1702*4882a593Smuzhiyun
1703*4882a593Smuzhiyun smb->AndXCommand = 0xFF; /* none */
1704*4882a593Smuzhiyun smb->Fid = rdata->cfile->fid.netfid;
1705*4882a593Smuzhiyun smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1706*4882a593Smuzhiyun if (wct == 12)
1707*4882a593Smuzhiyun smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1708*4882a593Smuzhiyun smb->Remaining = 0;
1709*4882a593Smuzhiyun smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1710*4882a593Smuzhiyun smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1711*4882a593Smuzhiyun if (wct == 12)
1712*4882a593Smuzhiyun smb->ByteCount = 0;
1713*4882a593Smuzhiyun else {
1714*4882a593Smuzhiyun /* old style read */
1715*4882a593Smuzhiyun struct smb_com_readx_req *smbr =
1716*4882a593Smuzhiyun (struct smb_com_readx_req *)smb;
1717*4882a593Smuzhiyun smbr->ByteCount = 0;
1718*4882a593Smuzhiyun }
1719*4882a593Smuzhiyun
1720*4882a593Smuzhiyun /* 4 for RFC1001 length + 1 for BCC */
1721*4882a593Smuzhiyun rdata->iov[0].iov_base = smb;
1722*4882a593Smuzhiyun rdata->iov[0].iov_len = 4;
1723*4882a593Smuzhiyun rdata->iov[1].iov_base = (char *)smb + 4;
1724*4882a593Smuzhiyun rdata->iov[1].iov_len = get_rfc1002_length(smb);
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun kref_get(&rdata->refcount);
1727*4882a593Smuzhiyun rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
1728*4882a593Smuzhiyun cifs_readv_callback, NULL, rdata, 0, NULL);
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun if (rc == 0)
1731*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1732*4882a593Smuzhiyun else
1733*4882a593Smuzhiyun kref_put(&rdata->refcount, cifs_readdata_release);
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun cifs_small_buf_release(smb);
1736*4882a593Smuzhiyun return rc;
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun int
CIFSSMBRead(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,char ** buf,int * pbuf_type)1740*4882a593Smuzhiyun CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1741*4882a593Smuzhiyun unsigned int *nbytes, char **buf, int *pbuf_type)
1742*4882a593Smuzhiyun {
1743*4882a593Smuzhiyun int rc = -EACCES;
1744*4882a593Smuzhiyun READ_REQ *pSMB = NULL;
1745*4882a593Smuzhiyun READ_RSP *pSMBr = NULL;
1746*4882a593Smuzhiyun char *pReadData = NULL;
1747*4882a593Smuzhiyun int wct;
1748*4882a593Smuzhiyun int resp_buf_type = 0;
1749*4882a593Smuzhiyun struct kvec iov[1];
1750*4882a593Smuzhiyun struct kvec rsp_iov;
1751*4882a593Smuzhiyun __u32 pid = io_parms->pid;
1752*4882a593Smuzhiyun __u16 netfid = io_parms->netfid;
1753*4882a593Smuzhiyun __u64 offset = io_parms->offset;
1754*4882a593Smuzhiyun struct cifs_tcon *tcon = io_parms->tcon;
1755*4882a593Smuzhiyun unsigned int count = io_parms->length;
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
1758*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_FILES)
1759*4882a593Smuzhiyun wct = 12;
1760*4882a593Smuzhiyun else {
1761*4882a593Smuzhiyun wct = 10; /* old style read */
1762*4882a593Smuzhiyun if ((offset >> 32) > 0) {
1763*4882a593Smuzhiyun /* can not handle this big offset for old */
1764*4882a593Smuzhiyun return -EIO;
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun
1768*4882a593Smuzhiyun *nbytes = 0;
1769*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1770*4882a593Smuzhiyun if (rc)
1771*4882a593Smuzhiyun return rc;
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1774*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun /* tcon and ses pointer are checked in smb_init */
1777*4882a593Smuzhiyun if (tcon->ses->server == NULL)
1778*4882a593Smuzhiyun return -ECONNABORTED;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
1781*4882a593Smuzhiyun pSMB->Fid = netfid;
1782*4882a593Smuzhiyun pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1783*4882a593Smuzhiyun if (wct == 12)
1784*4882a593Smuzhiyun pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun pSMB->Remaining = 0;
1787*4882a593Smuzhiyun pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1788*4882a593Smuzhiyun pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1789*4882a593Smuzhiyun if (wct == 12)
1790*4882a593Smuzhiyun pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1791*4882a593Smuzhiyun else {
1792*4882a593Smuzhiyun /* old style read */
1793*4882a593Smuzhiyun struct smb_com_readx_req *pSMBW =
1794*4882a593Smuzhiyun (struct smb_com_readx_req *)pSMB;
1795*4882a593Smuzhiyun pSMBW->ByteCount = 0;
1796*4882a593Smuzhiyun }
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun iov[0].iov_base = (char *)pSMB;
1799*4882a593Smuzhiyun iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1800*4882a593Smuzhiyun rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1801*4882a593Smuzhiyun CIFS_LOG_ERROR, &rsp_iov);
1802*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
1803*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1804*4882a593Smuzhiyun pSMBr = (READ_RSP *)rsp_iov.iov_base;
1805*4882a593Smuzhiyun if (rc) {
1806*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in read = %d\n", rc);
1807*4882a593Smuzhiyun } else {
1808*4882a593Smuzhiyun int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1809*4882a593Smuzhiyun data_length = data_length << 16;
1810*4882a593Smuzhiyun data_length += le16_to_cpu(pSMBr->DataLength);
1811*4882a593Smuzhiyun *nbytes = data_length;
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun /*check that DataLength would not go beyond end of SMB */
1814*4882a593Smuzhiyun if ((data_length > CIFSMaxBufSize)
1815*4882a593Smuzhiyun || (data_length > count)) {
1816*4882a593Smuzhiyun cifs_dbg(FYI, "bad length %d for count %d\n",
1817*4882a593Smuzhiyun data_length, count);
1818*4882a593Smuzhiyun rc = -EIO;
1819*4882a593Smuzhiyun *nbytes = 0;
1820*4882a593Smuzhiyun } else {
1821*4882a593Smuzhiyun pReadData = (char *) (&pSMBr->hdr.Protocol) +
1822*4882a593Smuzhiyun le16_to_cpu(pSMBr->DataOffset);
1823*4882a593Smuzhiyun /* if (rc = copy_to_user(buf, pReadData, data_length)) {
1824*4882a593Smuzhiyun cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
1825*4882a593Smuzhiyun rc = -EFAULT;
1826*4882a593Smuzhiyun }*/ /* can not use copy_to_user when using page cache*/
1827*4882a593Smuzhiyun if (*buf)
1828*4882a593Smuzhiyun memcpy(*buf, pReadData, data_length);
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun if (*buf) {
1833*4882a593Smuzhiyun free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
1834*4882a593Smuzhiyun } else if (resp_buf_type != CIFS_NO_BUFFER) {
1835*4882a593Smuzhiyun /* return buffer to caller to free */
1836*4882a593Smuzhiyun *buf = rsp_iov.iov_base;
1837*4882a593Smuzhiyun if (resp_buf_type == CIFS_SMALL_BUFFER)
1838*4882a593Smuzhiyun *pbuf_type = CIFS_SMALL_BUFFER;
1839*4882a593Smuzhiyun else if (resp_buf_type == CIFS_LARGE_BUFFER)
1840*4882a593Smuzhiyun *pbuf_type = CIFS_LARGE_BUFFER;
1841*4882a593Smuzhiyun } /* else no valid buffer on return - leave as null */
1842*4882a593Smuzhiyun
1843*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
1844*4882a593Smuzhiyun since file handle passed in no longer valid */
1845*4882a593Smuzhiyun return rc;
1846*4882a593Smuzhiyun }
1847*4882a593Smuzhiyun
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun int
CIFSSMBWrite(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,const char * buf)1850*4882a593Smuzhiyun CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
1851*4882a593Smuzhiyun unsigned int *nbytes, const char *buf)
1852*4882a593Smuzhiyun {
1853*4882a593Smuzhiyun int rc = -EACCES;
1854*4882a593Smuzhiyun WRITE_REQ *pSMB = NULL;
1855*4882a593Smuzhiyun WRITE_RSP *pSMBr = NULL;
1856*4882a593Smuzhiyun int bytes_returned, wct;
1857*4882a593Smuzhiyun __u32 bytes_sent;
1858*4882a593Smuzhiyun __u16 byte_count;
1859*4882a593Smuzhiyun __u32 pid = io_parms->pid;
1860*4882a593Smuzhiyun __u16 netfid = io_parms->netfid;
1861*4882a593Smuzhiyun __u64 offset = io_parms->offset;
1862*4882a593Smuzhiyun struct cifs_tcon *tcon = io_parms->tcon;
1863*4882a593Smuzhiyun unsigned int count = io_parms->length;
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun *nbytes = 0;
1866*4882a593Smuzhiyun
1867*4882a593Smuzhiyun /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
1868*4882a593Smuzhiyun if (tcon->ses == NULL)
1869*4882a593Smuzhiyun return -ECONNABORTED;
1870*4882a593Smuzhiyun
1871*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_FILES)
1872*4882a593Smuzhiyun wct = 14;
1873*4882a593Smuzhiyun else {
1874*4882a593Smuzhiyun wct = 12;
1875*4882a593Smuzhiyun if ((offset >> 32) > 0) {
1876*4882a593Smuzhiyun /* can not handle big offset for old srv */
1877*4882a593Smuzhiyun return -EIO;
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun }
1880*4882a593Smuzhiyun
1881*4882a593Smuzhiyun rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1882*4882a593Smuzhiyun (void **) &pSMBr);
1883*4882a593Smuzhiyun if (rc)
1884*4882a593Smuzhiyun return rc;
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1887*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun /* tcon and ses pointer are checked in smb_init */
1890*4882a593Smuzhiyun if (tcon->ses->server == NULL)
1891*4882a593Smuzhiyun return -ECONNABORTED;
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
1894*4882a593Smuzhiyun pSMB->Fid = netfid;
1895*4882a593Smuzhiyun pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1896*4882a593Smuzhiyun if (wct == 14)
1897*4882a593Smuzhiyun pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun pSMB->Reserved = 0xFFFFFFFF;
1900*4882a593Smuzhiyun pSMB->WriteMode = 0;
1901*4882a593Smuzhiyun pSMB->Remaining = 0;
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun /* Can increase buffer size if buffer is big enough in some cases ie we
1904*4882a593Smuzhiyun can send more if LARGE_WRITE_X capability returned by the server and if
1905*4882a593Smuzhiyun our buffer is big enough or if we convert to iovecs on socket writes
1906*4882a593Smuzhiyun and eliminate the copy to the CIFS buffer */
1907*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1908*4882a593Smuzhiyun bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1909*4882a593Smuzhiyun } else {
1910*4882a593Smuzhiyun bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1911*4882a593Smuzhiyun & ~0xFF;
1912*4882a593Smuzhiyun }
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun if (bytes_sent > count)
1915*4882a593Smuzhiyun bytes_sent = count;
1916*4882a593Smuzhiyun pSMB->DataOffset =
1917*4882a593Smuzhiyun cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1918*4882a593Smuzhiyun if (buf)
1919*4882a593Smuzhiyun memcpy(pSMB->Data, buf, bytes_sent);
1920*4882a593Smuzhiyun else if (count != 0) {
1921*4882a593Smuzhiyun /* No buffer */
1922*4882a593Smuzhiyun cifs_buf_release(pSMB);
1923*4882a593Smuzhiyun return -EINVAL;
1924*4882a593Smuzhiyun } /* else setting file size with write of zero bytes */
1925*4882a593Smuzhiyun if (wct == 14)
1926*4882a593Smuzhiyun byte_count = bytes_sent + 1; /* pad */
1927*4882a593Smuzhiyun else /* wct == 12 */
1928*4882a593Smuzhiyun byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1929*4882a593Smuzhiyun
1930*4882a593Smuzhiyun pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1931*4882a593Smuzhiyun pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1932*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun if (wct == 14)
1935*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
1936*4882a593Smuzhiyun else { /* old style write has byte count 4 bytes earlier
1937*4882a593Smuzhiyun so 4 bytes pad */
1938*4882a593Smuzhiyun struct smb_com_writex_req *pSMBW =
1939*4882a593Smuzhiyun (struct smb_com_writex_req *)pSMB;
1940*4882a593Smuzhiyun pSMBW->ByteCount = cpu_to_le16(byte_count);
1941*4882a593Smuzhiyun }
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1944*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1945*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
1946*4882a593Smuzhiyun if (rc) {
1947*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in write = %d\n", rc);
1948*4882a593Smuzhiyun } else {
1949*4882a593Smuzhiyun *nbytes = le16_to_cpu(pSMBr->CountHigh);
1950*4882a593Smuzhiyun *nbytes = (*nbytes) << 16;
1951*4882a593Smuzhiyun *nbytes += le16_to_cpu(pSMBr->Count);
1952*4882a593Smuzhiyun
1953*4882a593Smuzhiyun /*
1954*4882a593Smuzhiyun * Mask off high 16 bits when bytes written as returned by the
1955*4882a593Smuzhiyun * server is greater than bytes requested by the client. Some
1956*4882a593Smuzhiyun * OS/2 servers are known to set incorrect CountHigh values.
1957*4882a593Smuzhiyun */
1958*4882a593Smuzhiyun if (*nbytes > count)
1959*4882a593Smuzhiyun *nbytes &= 0xFFFF;
1960*4882a593Smuzhiyun }
1961*4882a593Smuzhiyun
1962*4882a593Smuzhiyun cifs_buf_release(pSMB);
1963*4882a593Smuzhiyun
1964*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
1965*4882a593Smuzhiyun since file handle passed in no longer valid */
1966*4882a593Smuzhiyun
1967*4882a593Smuzhiyun return rc;
1968*4882a593Smuzhiyun }
1969*4882a593Smuzhiyun
1970*4882a593Smuzhiyun void
cifs_writedata_release(struct kref * refcount)1971*4882a593Smuzhiyun cifs_writedata_release(struct kref *refcount)
1972*4882a593Smuzhiyun {
1973*4882a593Smuzhiyun struct cifs_writedata *wdata = container_of(refcount,
1974*4882a593Smuzhiyun struct cifs_writedata, refcount);
1975*4882a593Smuzhiyun #ifdef CONFIG_CIFS_SMB_DIRECT
1976*4882a593Smuzhiyun if (wdata->mr) {
1977*4882a593Smuzhiyun smbd_deregister_mr(wdata->mr);
1978*4882a593Smuzhiyun wdata->mr = NULL;
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun #endif
1981*4882a593Smuzhiyun
1982*4882a593Smuzhiyun if (wdata->cfile)
1983*4882a593Smuzhiyun cifsFileInfo_put(wdata->cfile);
1984*4882a593Smuzhiyun
1985*4882a593Smuzhiyun kvfree(wdata->pages);
1986*4882a593Smuzhiyun kfree(wdata);
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun
1989*4882a593Smuzhiyun /*
1990*4882a593Smuzhiyun * Write failed with a retryable error. Resend the write request. It's also
1991*4882a593Smuzhiyun * possible that the page was redirtied so re-clean the page.
1992*4882a593Smuzhiyun */
1993*4882a593Smuzhiyun static void
cifs_writev_requeue(struct cifs_writedata * wdata)1994*4882a593Smuzhiyun cifs_writev_requeue(struct cifs_writedata *wdata)
1995*4882a593Smuzhiyun {
1996*4882a593Smuzhiyun int i, rc = 0;
1997*4882a593Smuzhiyun struct inode *inode = d_inode(wdata->cfile->dentry);
1998*4882a593Smuzhiyun struct TCP_Server_Info *server;
1999*4882a593Smuzhiyun unsigned int rest_len;
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun server = tlink_tcon(wdata->cfile->tlink)->ses->server;
2002*4882a593Smuzhiyun i = 0;
2003*4882a593Smuzhiyun rest_len = wdata->bytes;
2004*4882a593Smuzhiyun do {
2005*4882a593Smuzhiyun struct cifs_writedata *wdata2;
2006*4882a593Smuzhiyun unsigned int j, nr_pages, wsize, tailsz, cur_len;
2007*4882a593Smuzhiyun
2008*4882a593Smuzhiyun wsize = server->ops->wp_retry_size(inode);
2009*4882a593Smuzhiyun if (wsize < rest_len) {
2010*4882a593Smuzhiyun nr_pages = wsize / PAGE_SIZE;
2011*4882a593Smuzhiyun if (!nr_pages) {
2012*4882a593Smuzhiyun rc = -ENOTSUPP;
2013*4882a593Smuzhiyun break;
2014*4882a593Smuzhiyun }
2015*4882a593Smuzhiyun cur_len = nr_pages * PAGE_SIZE;
2016*4882a593Smuzhiyun tailsz = PAGE_SIZE;
2017*4882a593Smuzhiyun } else {
2018*4882a593Smuzhiyun nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
2019*4882a593Smuzhiyun cur_len = rest_len;
2020*4882a593Smuzhiyun tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2024*4882a593Smuzhiyun if (!wdata2) {
2025*4882a593Smuzhiyun rc = -ENOMEM;
2026*4882a593Smuzhiyun break;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun for (j = 0; j < nr_pages; j++) {
2030*4882a593Smuzhiyun wdata2->pages[j] = wdata->pages[i + j];
2031*4882a593Smuzhiyun lock_page(wdata2->pages[j]);
2032*4882a593Smuzhiyun clear_page_dirty_for_io(wdata2->pages[j]);
2033*4882a593Smuzhiyun }
2034*4882a593Smuzhiyun
2035*4882a593Smuzhiyun wdata2->sync_mode = wdata->sync_mode;
2036*4882a593Smuzhiyun wdata2->nr_pages = nr_pages;
2037*4882a593Smuzhiyun wdata2->offset = page_offset(wdata2->pages[0]);
2038*4882a593Smuzhiyun wdata2->pagesz = PAGE_SIZE;
2039*4882a593Smuzhiyun wdata2->tailsz = tailsz;
2040*4882a593Smuzhiyun wdata2->bytes = cur_len;
2041*4882a593Smuzhiyun
2042*4882a593Smuzhiyun rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
2043*4882a593Smuzhiyun &wdata2->cfile);
2044*4882a593Smuzhiyun if (!wdata2->cfile) {
2045*4882a593Smuzhiyun cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
2046*4882a593Smuzhiyun rc);
2047*4882a593Smuzhiyun if (!is_retryable_error(rc))
2048*4882a593Smuzhiyun rc = -EBADF;
2049*4882a593Smuzhiyun } else {
2050*4882a593Smuzhiyun wdata2->pid = wdata2->cfile->pid;
2051*4882a593Smuzhiyun rc = server->ops->async_writev(wdata2,
2052*4882a593Smuzhiyun cifs_writedata_release);
2053*4882a593Smuzhiyun }
2054*4882a593Smuzhiyun
2055*4882a593Smuzhiyun for (j = 0; j < nr_pages; j++) {
2056*4882a593Smuzhiyun unlock_page(wdata2->pages[j]);
2057*4882a593Smuzhiyun if (rc != 0 && !is_retryable_error(rc)) {
2058*4882a593Smuzhiyun SetPageError(wdata2->pages[j]);
2059*4882a593Smuzhiyun end_page_writeback(wdata2->pages[j]);
2060*4882a593Smuzhiyun put_page(wdata2->pages[j]);
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun kref_put(&wdata2->refcount, cifs_writedata_release);
2065*4882a593Smuzhiyun if (rc) {
2066*4882a593Smuzhiyun if (is_retryable_error(rc))
2067*4882a593Smuzhiyun continue;
2068*4882a593Smuzhiyun i += nr_pages;
2069*4882a593Smuzhiyun break;
2070*4882a593Smuzhiyun }
2071*4882a593Smuzhiyun
2072*4882a593Smuzhiyun rest_len -= cur_len;
2073*4882a593Smuzhiyun i += nr_pages;
2074*4882a593Smuzhiyun } while (i < wdata->nr_pages);
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun /* cleanup remaining pages from the original wdata */
2077*4882a593Smuzhiyun for (; i < wdata->nr_pages; i++) {
2078*4882a593Smuzhiyun SetPageError(wdata->pages[i]);
2079*4882a593Smuzhiyun end_page_writeback(wdata->pages[i]);
2080*4882a593Smuzhiyun put_page(wdata->pages[i]);
2081*4882a593Smuzhiyun }
2082*4882a593Smuzhiyun
2083*4882a593Smuzhiyun if (rc != 0 && !is_retryable_error(rc))
2084*4882a593Smuzhiyun mapping_set_error(inode->i_mapping, rc);
2085*4882a593Smuzhiyun kref_put(&wdata->refcount, cifs_writedata_release);
2086*4882a593Smuzhiyun }
2087*4882a593Smuzhiyun
2088*4882a593Smuzhiyun void
cifs_writev_complete(struct work_struct * work)2089*4882a593Smuzhiyun cifs_writev_complete(struct work_struct *work)
2090*4882a593Smuzhiyun {
2091*4882a593Smuzhiyun struct cifs_writedata *wdata = container_of(work,
2092*4882a593Smuzhiyun struct cifs_writedata, work);
2093*4882a593Smuzhiyun struct inode *inode = d_inode(wdata->cfile->dentry);
2094*4882a593Smuzhiyun int i = 0;
2095*4882a593Smuzhiyun
2096*4882a593Smuzhiyun if (wdata->result == 0) {
2097*4882a593Smuzhiyun spin_lock(&inode->i_lock);
2098*4882a593Smuzhiyun cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2099*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
2100*4882a593Smuzhiyun cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2101*4882a593Smuzhiyun wdata->bytes);
2102*4882a593Smuzhiyun } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2103*4882a593Smuzhiyun return cifs_writev_requeue(wdata);
2104*4882a593Smuzhiyun
2105*4882a593Smuzhiyun for (i = 0; i < wdata->nr_pages; i++) {
2106*4882a593Smuzhiyun struct page *page = wdata->pages[i];
2107*4882a593Smuzhiyun if (wdata->result == -EAGAIN)
2108*4882a593Smuzhiyun __set_page_dirty_nobuffers(page);
2109*4882a593Smuzhiyun else if (wdata->result < 0)
2110*4882a593Smuzhiyun SetPageError(page);
2111*4882a593Smuzhiyun end_page_writeback(page);
2112*4882a593Smuzhiyun put_page(page);
2113*4882a593Smuzhiyun }
2114*4882a593Smuzhiyun if (wdata->result != -EAGAIN)
2115*4882a593Smuzhiyun mapping_set_error(inode->i_mapping, wdata->result);
2116*4882a593Smuzhiyun kref_put(&wdata->refcount, cifs_writedata_release);
2117*4882a593Smuzhiyun }
2118*4882a593Smuzhiyun
2119*4882a593Smuzhiyun struct cifs_writedata *
cifs_writedata_alloc(unsigned int nr_pages,work_func_t complete)2120*4882a593Smuzhiyun cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
2121*4882a593Smuzhiyun {
2122*4882a593Smuzhiyun struct page **pages =
2123*4882a593Smuzhiyun kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
2124*4882a593Smuzhiyun if (pages)
2125*4882a593Smuzhiyun return cifs_writedata_direct_alloc(pages, complete);
2126*4882a593Smuzhiyun
2127*4882a593Smuzhiyun return NULL;
2128*4882a593Smuzhiyun }
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun struct cifs_writedata *
cifs_writedata_direct_alloc(struct page ** pages,work_func_t complete)2131*4882a593Smuzhiyun cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2132*4882a593Smuzhiyun {
2133*4882a593Smuzhiyun struct cifs_writedata *wdata;
2134*4882a593Smuzhiyun
2135*4882a593Smuzhiyun wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
2136*4882a593Smuzhiyun if (wdata != NULL) {
2137*4882a593Smuzhiyun wdata->pages = pages;
2138*4882a593Smuzhiyun kref_init(&wdata->refcount);
2139*4882a593Smuzhiyun INIT_LIST_HEAD(&wdata->list);
2140*4882a593Smuzhiyun init_completion(&wdata->done);
2141*4882a593Smuzhiyun INIT_WORK(&wdata->work, complete);
2142*4882a593Smuzhiyun }
2143*4882a593Smuzhiyun return wdata;
2144*4882a593Smuzhiyun }
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun /*
2147*4882a593Smuzhiyun * Check the mid_state and signature on received buffer (if any), and queue the
2148*4882a593Smuzhiyun * workqueue completion task.
2149*4882a593Smuzhiyun */
2150*4882a593Smuzhiyun static void
cifs_writev_callback(struct mid_q_entry * mid)2151*4882a593Smuzhiyun cifs_writev_callback(struct mid_q_entry *mid)
2152*4882a593Smuzhiyun {
2153*4882a593Smuzhiyun struct cifs_writedata *wdata = mid->callback_data;
2154*4882a593Smuzhiyun struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2155*4882a593Smuzhiyun unsigned int written;
2156*4882a593Smuzhiyun WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2157*4882a593Smuzhiyun struct cifs_credits credits = { .value = 1, .instance = 0 };
2158*4882a593Smuzhiyun
2159*4882a593Smuzhiyun switch (mid->mid_state) {
2160*4882a593Smuzhiyun case MID_RESPONSE_RECEIVED:
2161*4882a593Smuzhiyun wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2162*4882a593Smuzhiyun if (wdata->result != 0)
2163*4882a593Smuzhiyun break;
2164*4882a593Smuzhiyun
2165*4882a593Smuzhiyun written = le16_to_cpu(smb->CountHigh);
2166*4882a593Smuzhiyun written <<= 16;
2167*4882a593Smuzhiyun written += le16_to_cpu(smb->Count);
2168*4882a593Smuzhiyun /*
2169*4882a593Smuzhiyun * Mask off high 16 bits when bytes written as returned
2170*4882a593Smuzhiyun * by the server is greater than bytes requested by the
2171*4882a593Smuzhiyun * client. OS/2 servers are known to set incorrect
2172*4882a593Smuzhiyun * CountHigh values.
2173*4882a593Smuzhiyun */
2174*4882a593Smuzhiyun if (written > wdata->bytes)
2175*4882a593Smuzhiyun written &= 0xFFFF;
2176*4882a593Smuzhiyun
2177*4882a593Smuzhiyun if (written < wdata->bytes)
2178*4882a593Smuzhiyun wdata->result = -ENOSPC;
2179*4882a593Smuzhiyun else
2180*4882a593Smuzhiyun wdata->bytes = written;
2181*4882a593Smuzhiyun break;
2182*4882a593Smuzhiyun case MID_REQUEST_SUBMITTED:
2183*4882a593Smuzhiyun case MID_RETRY_NEEDED:
2184*4882a593Smuzhiyun wdata->result = -EAGAIN;
2185*4882a593Smuzhiyun break;
2186*4882a593Smuzhiyun default:
2187*4882a593Smuzhiyun wdata->result = -EIO;
2188*4882a593Smuzhiyun break;
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun
2191*4882a593Smuzhiyun queue_work(cifsiod_wq, &wdata->work);
2192*4882a593Smuzhiyun DeleteMidQEntry(mid);
2193*4882a593Smuzhiyun add_credits(tcon->ses->server, &credits, 0);
2194*4882a593Smuzhiyun }
2195*4882a593Smuzhiyun
2196*4882a593Smuzhiyun /* cifs_async_writev - send an async write, and set up mid to handle result */
2197*4882a593Smuzhiyun int
cifs_async_writev(struct cifs_writedata * wdata,void (* release)(struct kref * kref))2198*4882a593Smuzhiyun cifs_async_writev(struct cifs_writedata *wdata,
2199*4882a593Smuzhiyun void (*release)(struct kref *kref))
2200*4882a593Smuzhiyun {
2201*4882a593Smuzhiyun int rc = -EACCES;
2202*4882a593Smuzhiyun WRITE_REQ *smb = NULL;
2203*4882a593Smuzhiyun int wct;
2204*4882a593Smuzhiyun struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2205*4882a593Smuzhiyun struct kvec iov[2];
2206*4882a593Smuzhiyun struct smb_rqst rqst = { };
2207*4882a593Smuzhiyun
2208*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2209*4882a593Smuzhiyun wct = 14;
2210*4882a593Smuzhiyun } else {
2211*4882a593Smuzhiyun wct = 12;
2212*4882a593Smuzhiyun if (wdata->offset >> 32 > 0) {
2213*4882a593Smuzhiyun /* can not handle big offset for old srv */
2214*4882a593Smuzhiyun return -EIO;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun }
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2219*4882a593Smuzhiyun if (rc)
2220*4882a593Smuzhiyun goto async_writev_out;
2221*4882a593Smuzhiyun
2222*4882a593Smuzhiyun smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2223*4882a593Smuzhiyun smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun smb->AndXCommand = 0xFF; /* none */
2226*4882a593Smuzhiyun smb->Fid = wdata->cfile->fid.netfid;
2227*4882a593Smuzhiyun smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2228*4882a593Smuzhiyun if (wct == 14)
2229*4882a593Smuzhiyun smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2230*4882a593Smuzhiyun smb->Reserved = 0xFFFFFFFF;
2231*4882a593Smuzhiyun smb->WriteMode = 0;
2232*4882a593Smuzhiyun smb->Remaining = 0;
2233*4882a593Smuzhiyun
2234*4882a593Smuzhiyun smb->DataOffset =
2235*4882a593Smuzhiyun cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun /* 4 for RFC1001 length + 1 for BCC */
2238*4882a593Smuzhiyun iov[0].iov_len = 4;
2239*4882a593Smuzhiyun iov[0].iov_base = smb;
2240*4882a593Smuzhiyun iov[1].iov_len = get_rfc1002_length(smb) + 1;
2241*4882a593Smuzhiyun iov[1].iov_base = (char *)smb + 4;
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun rqst.rq_iov = iov;
2244*4882a593Smuzhiyun rqst.rq_nvec = 2;
2245*4882a593Smuzhiyun rqst.rq_pages = wdata->pages;
2246*4882a593Smuzhiyun rqst.rq_offset = wdata->page_offset;
2247*4882a593Smuzhiyun rqst.rq_npages = wdata->nr_pages;
2248*4882a593Smuzhiyun rqst.rq_pagesz = wdata->pagesz;
2249*4882a593Smuzhiyun rqst.rq_tailsz = wdata->tailsz;
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun cifs_dbg(FYI, "async write at %llu %u bytes\n",
2252*4882a593Smuzhiyun wdata->offset, wdata->bytes);
2253*4882a593Smuzhiyun
2254*4882a593Smuzhiyun smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2255*4882a593Smuzhiyun smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2256*4882a593Smuzhiyun
2257*4882a593Smuzhiyun if (wct == 14) {
2258*4882a593Smuzhiyun inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2259*4882a593Smuzhiyun put_bcc(wdata->bytes + 1, &smb->hdr);
2260*4882a593Smuzhiyun } else {
2261*4882a593Smuzhiyun /* wct == 12 */
2262*4882a593Smuzhiyun struct smb_com_writex_req *smbw =
2263*4882a593Smuzhiyun (struct smb_com_writex_req *)smb;
2264*4882a593Smuzhiyun inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2265*4882a593Smuzhiyun put_bcc(wdata->bytes + 5, &smbw->hdr);
2266*4882a593Smuzhiyun iov[1].iov_len += 4; /* pad bigger by four bytes */
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun
2269*4882a593Smuzhiyun kref_get(&wdata->refcount);
2270*4882a593Smuzhiyun rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
2271*4882a593Smuzhiyun cifs_writev_callback, NULL, wdata, 0, NULL);
2272*4882a593Smuzhiyun
2273*4882a593Smuzhiyun if (rc == 0)
2274*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2275*4882a593Smuzhiyun else
2276*4882a593Smuzhiyun kref_put(&wdata->refcount, release);
2277*4882a593Smuzhiyun
2278*4882a593Smuzhiyun async_writev_out:
2279*4882a593Smuzhiyun cifs_small_buf_release(smb);
2280*4882a593Smuzhiyun return rc;
2281*4882a593Smuzhiyun }
2282*4882a593Smuzhiyun
2283*4882a593Smuzhiyun int
CIFSSMBWrite2(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,struct kvec * iov,int n_vec)2284*4882a593Smuzhiyun CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
2285*4882a593Smuzhiyun unsigned int *nbytes, struct kvec *iov, int n_vec)
2286*4882a593Smuzhiyun {
2287*4882a593Smuzhiyun int rc;
2288*4882a593Smuzhiyun WRITE_REQ *pSMB = NULL;
2289*4882a593Smuzhiyun int wct;
2290*4882a593Smuzhiyun int smb_hdr_len;
2291*4882a593Smuzhiyun int resp_buf_type = 0;
2292*4882a593Smuzhiyun __u32 pid = io_parms->pid;
2293*4882a593Smuzhiyun __u16 netfid = io_parms->netfid;
2294*4882a593Smuzhiyun __u64 offset = io_parms->offset;
2295*4882a593Smuzhiyun struct cifs_tcon *tcon = io_parms->tcon;
2296*4882a593Smuzhiyun unsigned int count = io_parms->length;
2297*4882a593Smuzhiyun struct kvec rsp_iov;
2298*4882a593Smuzhiyun
2299*4882a593Smuzhiyun *nbytes = 0;
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
2302*4882a593Smuzhiyun
2303*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2304*4882a593Smuzhiyun wct = 14;
2305*4882a593Smuzhiyun } else {
2306*4882a593Smuzhiyun wct = 12;
2307*4882a593Smuzhiyun if ((offset >> 32) > 0) {
2308*4882a593Smuzhiyun /* can not handle big offset for old srv */
2309*4882a593Smuzhiyun return -EIO;
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun }
2312*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
2313*4882a593Smuzhiyun if (rc)
2314*4882a593Smuzhiyun return rc;
2315*4882a593Smuzhiyun
2316*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2317*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun /* tcon and ses pointer are checked in smb_init */
2320*4882a593Smuzhiyun if (tcon->ses->server == NULL)
2321*4882a593Smuzhiyun return -ECONNABORTED;
2322*4882a593Smuzhiyun
2323*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
2324*4882a593Smuzhiyun pSMB->Fid = netfid;
2325*4882a593Smuzhiyun pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
2326*4882a593Smuzhiyun if (wct == 14)
2327*4882a593Smuzhiyun pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
2328*4882a593Smuzhiyun pSMB->Reserved = 0xFFFFFFFF;
2329*4882a593Smuzhiyun pSMB->WriteMode = 0;
2330*4882a593Smuzhiyun pSMB->Remaining = 0;
2331*4882a593Smuzhiyun
2332*4882a593Smuzhiyun pSMB->DataOffset =
2333*4882a593Smuzhiyun cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2334*4882a593Smuzhiyun
2335*4882a593Smuzhiyun pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2336*4882a593Smuzhiyun pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2337*4882a593Smuzhiyun /* header + 1 byte pad */
2338*4882a593Smuzhiyun smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
2339*4882a593Smuzhiyun if (wct == 14)
2340*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count + 1);
2341*4882a593Smuzhiyun else /* wct == 12 */
2342*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
2343*4882a593Smuzhiyun if (wct == 14)
2344*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count + 1);
2345*4882a593Smuzhiyun else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2346*4882a593Smuzhiyun struct smb_com_writex_req *pSMBW =
2347*4882a593Smuzhiyun (struct smb_com_writex_req *)pSMB;
2348*4882a593Smuzhiyun pSMBW->ByteCount = cpu_to_le16(count + 5);
2349*4882a593Smuzhiyun }
2350*4882a593Smuzhiyun iov[0].iov_base = pSMB;
2351*4882a593Smuzhiyun if (wct == 14)
2352*4882a593Smuzhiyun iov[0].iov_len = smb_hdr_len + 4;
2353*4882a593Smuzhiyun else /* wct == 12 pad bigger by four bytes */
2354*4882a593Smuzhiyun iov[0].iov_len = smb_hdr_len + 8;
2355*4882a593Smuzhiyun
2356*4882a593Smuzhiyun rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2357*4882a593Smuzhiyun &rsp_iov);
2358*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2359*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
2360*4882a593Smuzhiyun if (rc) {
2361*4882a593Smuzhiyun cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
2362*4882a593Smuzhiyun } else if (resp_buf_type == 0) {
2363*4882a593Smuzhiyun /* presumably this can not happen, but best to be safe */
2364*4882a593Smuzhiyun rc = -EIO;
2365*4882a593Smuzhiyun } else {
2366*4882a593Smuzhiyun WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
2367*4882a593Smuzhiyun *nbytes = le16_to_cpu(pSMBr->CountHigh);
2368*4882a593Smuzhiyun *nbytes = (*nbytes) << 16;
2369*4882a593Smuzhiyun *nbytes += le16_to_cpu(pSMBr->Count);
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun /*
2372*4882a593Smuzhiyun * Mask off high 16 bits when bytes written as returned by the
2373*4882a593Smuzhiyun * server is greater than bytes requested by the client. OS/2
2374*4882a593Smuzhiyun * servers are known to set incorrect CountHigh values.
2375*4882a593Smuzhiyun */
2376*4882a593Smuzhiyun if (*nbytes > count)
2377*4882a593Smuzhiyun *nbytes &= 0xFFFF;
2378*4882a593Smuzhiyun }
2379*4882a593Smuzhiyun
2380*4882a593Smuzhiyun free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
2381*4882a593Smuzhiyun
2382*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
2383*4882a593Smuzhiyun since file handle passed in no longer valid */
2384*4882a593Smuzhiyun
2385*4882a593Smuzhiyun return rc;
2386*4882a593Smuzhiyun }
2387*4882a593Smuzhiyun
cifs_lockv(const unsigned int xid,struct cifs_tcon * tcon,const __u16 netfid,const __u8 lock_type,const __u32 num_unlock,const __u32 num_lock,LOCKING_ANDX_RANGE * buf)2388*4882a593Smuzhiyun int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2389*4882a593Smuzhiyun const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
2390*4882a593Smuzhiyun const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2391*4882a593Smuzhiyun {
2392*4882a593Smuzhiyun int rc = 0;
2393*4882a593Smuzhiyun LOCK_REQ *pSMB = NULL;
2394*4882a593Smuzhiyun struct kvec iov[2];
2395*4882a593Smuzhiyun struct kvec rsp_iov;
2396*4882a593Smuzhiyun int resp_buf_type;
2397*4882a593Smuzhiyun __u16 count;
2398*4882a593Smuzhiyun
2399*4882a593Smuzhiyun cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2400*4882a593Smuzhiyun num_lock, num_unlock);
2401*4882a593Smuzhiyun
2402*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2403*4882a593Smuzhiyun if (rc)
2404*4882a593Smuzhiyun return rc;
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun pSMB->Timeout = 0;
2407*4882a593Smuzhiyun pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2408*4882a593Smuzhiyun pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2409*4882a593Smuzhiyun pSMB->LockType = lock_type;
2410*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
2411*4882a593Smuzhiyun pSMB->Fid = netfid; /* netfid stays le */
2412*4882a593Smuzhiyun
2413*4882a593Smuzhiyun count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2414*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
2415*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
2416*4882a593Smuzhiyun
2417*4882a593Smuzhiyun iov[0].iov_base = (char *)pSMB;
2418*4882a593Smuzhiyun iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2419*4882a593Smuzhiyun (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2420*4882a593Smuzhiyun iov[1].iov_base = (char *)buf;
2421*4882a593Smuzhiyun iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2424*4882a593Smuzhiyun rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
2425*4882a593Smuzhiyun CIFS_NO_RSP_BUF, &rsp_iov);
2426*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2427*4882a593Smuzhiyun if (rc)
2428*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun return rc;
2431*4882a593Smuzhiyun }
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun int
CIFSSMBLock(const unsigned int xid,struct cifs_tcon * tcon,const __u16 smb_file_id,const __u32 netpid,const __u64 len,const __u64 offset,const __u32 numUnlock,const __u32 numLock,const __u8 lockType,const bool waitFlag,const __u8 oplock_level)2434*4882a593Smuzhiyun CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
2435*4882a593Smuzhiyun const __u16 smb_file_id, const __u32 netpid, const __u64 len,
2436*4882a593Smuzhiyun const __u64 offset, const __u32 numUnlock,
2437*4882a593Smuzhiyun const __u32 numLock, const __u8 lockType,
2438*4882a593Smuzhiyun const bool waitFlag, const __u8 oplock_level)
2439*4882a593Smuzhiyun {
2440*4882a593Smuzhiyun int rc = 0;
2441*4882a593Smuzhiyun LOCK_REQ *pSMB = NULL;
2442*4882a593Smuzhiyun /* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
2443*4882a593Smuzhiyun int bytes_returned;
2444*4882a593Smuzhiyun int flags = 0;
2445*4882a593Smuzhiyun __u16 count;
2446*4882a593Smuzhiyun
2447*4882a593Smuzhiyun cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2448*4882a593Smuzhiyun (int)waitFlag, numLock);
2449*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2450*4882a593Smuzhiyun
2451*4882a593Smuzhiyun if (rc)
2452*4882a593Smuzhiyun return rc;
2453*4882a593Smuzhiyun
2454*4882a593Smuzhiyun if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2455*4882a593Smuzhiyun /* no response expected */
2456*4882a593Smuzhiyun flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
2457*4882a593Smuzhiyun pSMB->Timeout = 0;
2458*4882a593Smuzhiyun } else if (waitFlag) {
2459*4882a593Smuzhiyun flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2460*4882a593Smuzhiyun pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2461*4882a593Smuzhiyun } else {
2462*4882a593Smuzhiyun pSMB->Timeout = 0;
2463*4882a593Smuzhiyun }
2464*4882a593Smuzhiyun
2465*4882a593Smuzhiyun pSMB->NumberOfLocks = cpu_to_le16(numLock);
2466*4882a593Smuzhiyun pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2467*4882a593Smuzhiyun pSMB->LockType = lockType;
2468*4882a593Smuzhiyun pSMB->OplockLevel = oplock_level;
2469*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF; /* none */
2470*4882a593Smuzhiyun pSMB->Fid = smb_file_id; /* netfid stays le */
2471*4882a593Smuzhiyun
2472*4882a593Smuzhiyun if ((numLock != 0) || (numUnlock != 0)) {
2473*4882a593Smuzhiyun pSMB->Locks[0].Pid = cpu_to_le16(netpid);
2474*4882a593Smuzhiyun /* BB where to store pid high? */
2475*4882a593Smuzhiyun pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2476*4882a593Smuzhiyun pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2477*4882a593Smuzhiyun pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2478*4882a593Smuzhiyun pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2479*4882a593Smuzhiyun count = sizeof(LOCKING_ANDX_RANGE);
2480*4882a593Smuzhiyun } else {
2481*4882a593Smuzhiyun /* oplock break */
2482*4882a593Smuzhiyun count = 0;
2483*4882a593Smuzhiyun }
2484*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
2485*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
2486*4882a593Smuzhiyun
2487*4882a593Smuzhiyun if (waitFlag)
2488*4882a593Smuzhiyun rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2489*4882a593Smuzhiyun (struct smb_hdr *) pSMB, &bytes_returned);
2490*4882a593Smuzhiyun else
2491*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
2492*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2493*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2494*4882a593Smuzhiyun if (rc)
2495*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
2496*4882a593Smuzhiyun
2497*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
2498*4882a593Smuzhiyun since file handle passed in no longer valid */
2499*4882a593Smuzhiyun return rc;
2500*4882a593Smuzhiyun }
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun int
CIFSSMBPosixLock(const unsigned int xid,struct cifs_tcon * tcon,const __u16 smb_file_id,const __u32 netpid,const loff_t start_offset,const __u64 len,struct file_lock * pLockData,const __u16 lock_type,const bool waitFlag)2503*4882a593Smuzhiyun CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
2504*4882a593Smuzhiyun const __u16 smb_file_id, const __u32 netpid,
2505*4882a593Smuzhiyun const loff_t start_offset, const __u64 len,
2506*4882a593Smuzhiyun struct file_lock *pLockData, const __u16 lock_type,
2507*4882a593Smuzhiyun const bool waitFlag)
2508*4882a593Smuzhiyun {
2509*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
2510*4882a593Smuzhiyun struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2511*4882a593Smuzhiyun struct cifs_posix_lock *parm_data;
2512*4882a593Smuzhiyun int rc = 0;
2513*4882a593Smuzhiyun int timeout = 0;
2514*4882a593Smuzhiyun int bytes_returned = 0;
2515*4882a593Smuzhiyun int resp_buf_type = 0;
2516*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
2517*4882a593Smuzhiyun struct kvec iov[1];
2518*4882a593Smuzhiyun struct kvec rsp_iov;
2519*4882a593Smuzhiyun
2520*4882a593Smuzhiyun cifs_dbg(FYI, "Posix Lock\n");
2521*4882a593Smuzhiyun
2522*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2523*4882a593Smuzhiyun
2524*4882a593Smuzhiyun if (rc)
2525*4882a593Smuzhiyun return rc;
2526*4882a593Smuzhiyun
2527*4882a593Smuzhiyun pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun params = 6;
2530*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
2531*4882a593Smuzhiyun pSMB->Reserved = 0;
2532*4882a593Smuzhiyun pSMB->Flags = 0;
2533*4882a593Smuzhiyun pSMB->Reserved2 = 0;
2534*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2535*4882a593Smuzhiyun offset = param_offset + params;
2536*4882a593Smuzhiyun
2537*4882a593Smuzhiyun count = sizeof(struct cifs_posix_lock);
2538*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
2539*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2540*4882a593Smuzhiyun pSMB->SetupCount = 1;
2541*4882a593Smuzhiyun pSMB->Reserved3 = 0;
2542*4882a593Smuzhiyun if (pLockData)
2543*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2544*4882a593Smuzhiyun else
2545*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2546*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
2547*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
2548*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
2549*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
2550*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
2551*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
2552*4882a593Smuzhiyun parm_data = (struct cifs_posix_lock *)
2553*4882a593Smuzhiyun (((char *) &pSMB->hdr.Protocol) + offset);
2554*4882a593Smuzhiyun
2555*4882a593Smuzhiyun parm_data->lock_type = cpu_to_le16(lock_type);
2556*4882a593Smuzhiyun if (waitFlag) {
2557*4882a593Smuzhiyun timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2558*4882a593Smuzhiyun parm_data->lock_flags = cpu_to_le16(1);
2559*4882a593Smuzhiyun pSMB->Timeout = cpu_to_le32(-1);
2560*4882a593Smuzhiyun } else
2561*4882a593Smuzhiyun pSMB->Timeout = 0;
2562*4882a593Smuzhiyun
2563*4882a593Smuzhiyun parm_data->pid = cpu_to_le32(netpid);
2564*4882a593Smuzhiyun parm_data->start = cpu_to_le64(start_offset);
2565*4882a593Smuzhiyun parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
2566*4882a593Smuzhiyun
2567*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
2568*4882a593Smuzhiyun pSMB->Fid = smb_file_id;
2569*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2570*4882a593Smuzhiyun pSMB->Reserved4 = 0;
2571*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
2572*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
2573*4882a593Smuzhiyun if (waitFlag) {
2574*4882a593Smuzhiyun rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2575*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned);
2576*4882a593Smuzhiyun } else {
2577*4882a593Smuzhiyun iov[0].iov_base = (char *)pSMB;
2578*4882a593Smuzhiyun iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2579*4882a593Smuzhiyun rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2580*4882a593Smuzhiyun &resp_buf_type, timeout, &rsp_iov);
2581*4882a593Smuzhiyun pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
2582*4882a593Smuzhiyun }
2583*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2584*4882a593Smuzhiyun
2585*4882a593Smuzhiyun if (rc) {
2586*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
2587*4882a593Smuzhiyun } else if (pLockData) {
2588*4882a593Smuzhiyun /* lock structure can be returned on get */
2589*4882a593Smuzhiyun __u16 data_offset;
2590*4882a593Smuzhiyun __u16 data_count;
2591*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2592*4882a593Smuzhiyun
2593*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2594*4882a593Smuzhiyun rc = -EIO; /* bad smb */
2595*4882a593Smuzhiyun goto plk_err_exit;
2596*4882a593Smuzhiyun }
2597*4882a593Smuzhiyun data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2598*4882a593Smuzhiyun data_count = le16_to_cpu(pSMBr->t2.DataCount);
2599*4882a593Smuzhiyun if (data_count < sizeof(struct cifs_posix_lock)) {
2600*4882a593Smuzhiyun rc = -EIO;
2601*4882a593Smuzhiyun goto plk_err_exit;
2602*4882a593Smuzhiyun }
2603*4882a593Smuzhiyun parm_data = (struct cifs_posix_lock *)
2604*4882a593Smuzhiyun ((char *)&pSMBr->hdr.Protocol + data_offset);
2605*4882a593Smuzhiyun if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
2606*4882a593Smuzhiyun pLockData->fl_type = F_UNLCK;
2607*4882a593Smuzhiyun else {
2608*4882a593Smuzhiyun if (parm_data->lock_type ==
2609*4882a593Smuzhiyun cpu_to_le16(CIFS_RDLCK))
2610*4882a593Smuzhiyun pLockData->fl_type = F_RDLCK;
2611*4882a593Smuzhiyun else if (parm_data->lock_type ==
2612*4882a593Smuzhiyun cpu_to_le16(CIFS_WRLCK))
2613*4882a593Smuzhiyun pLockData->fl_type = F_WRLCK;
2614*4882a593Smuzhiyun
2615*4882a593Smuzhiyun pLockData->fl_start = le64_to_cpu(parm_data->start);
2616*4882a593Smuzhiyun pLockData->fl_end = pLockData->fl_start +
2617*4882a593Smuzhiyun le64_to_cpu(parm_data->length) - 1;
2618*4882a593Smuzhiyun pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
2619*4882a593Smuzhiyun }
2620*4882a593Smuzhiyun }
2621*4882a593Smuzhiyun
2622*4882a593Smuzhiyun plk_err_exit:
2623*4882a593Smuzhiyun free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
2624*4882a593Smuzhiyun
2625*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
2626*4882a593Smuzhiyun since file handle passed in no longer valid */
2627*4882a593Smuzhiyun
2628*4882a593Smuzhiyun return rc;
2629*4882a593Smuzhiyun }
2630*4882a593Smuzhiyun
2631*4882a593Smuzhiyun
2632*4882a593Smuzhiyun int
CIFSSMBClose(const unsigned int xid,struct cifs_tcon * tcon,int smb_file_id)2633*4882a593Smuzhiyun CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2634*4882a593Smuzhiyun {
2635*4882a593Smuzhiyun int rc = 0;
2636*4882a593Smuzhiyun CLOSE_REQ *pSMB = NULL;
2637*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBClose\n");
2638*4882a593Smuzhiyun
2639*4882a593Smuzhiyun /* do not retry on dead session on close */
2640*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
2641*4882a593Smuzhiyun if (rc == -EAGAIN)
2642*4882a593Smuzhiyun return 0;
2643*4882a593Smuzhiyun if (rc)
2644*4882a593Smuzhiyun return rc;
2645*4882a593Smuzhiyun
2646*4882a593Smuzhiyun pSMB->FileID = (__u16) smb_file_id;
2647*4882a593Smuzhiyun pSMB->LastWriteTime = 0xFFFFFFFF;
2648*4882a593Smuzhiyun pSMB->ByteCount = 0;
2649*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2650*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2651*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
2652*4882a593Smuzhiyun if (rc) {
2653*4882a593Smuzhiyun if (rc != -EINTR) {
2654*4882a593Smuzhiyun /* EINTR is expected when user ctl-c to kill app */
2655*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in Close = %d\n", rc);
2656*4882a593Smuzhiyun }
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun
2659*4882a593Smuzhiyun /* Since session is dead, file will be closed on server already */
2660*4882a593Smuzhiyun if (rc == -EAGAIN)
2661*4882a593Smuzhiyun rc = 0;
2662*4882a593Smuzhiyun
2663*4882a593Smuzhiyun return rc;
2664*4882a593Smuzhiyun }
2665*4882a593Smuzhiyun
2666*4882a593Smuzhiyun int
CIFSSMBFlush(const unsigned int xid,struct cifs_tcon * tcon,int smb_file_id)2667*4882a593Smuzhiyun CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2668*4882a593Smuzhiyun {
2669*4882a593Smuzhiyun int rc = 0;
2670*4882a593Smuzhiyun FLUSH_REQ *pSMB = NULL;
2671*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBFlush\n");
2672*4882a593Smuzhiyun
2673*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2674*4882a593Smuzhiyun if (rc)
2675*4882a593Smuzhiyun return rc;
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun pSMB->FileID = (__u16) smb_file_id;
2678*4882a593Smuzhiyun pSMB->ByteCount = 0;
2679*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2680*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
2681*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
2682*4882a593Smuzhiyun if (rc)
2683*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun return rc;
2686*4882a593Smuzhiyun }
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun int
CIFSSMBRename(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)2689*4882a593Smuzhiyun CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2690*4882a593Smuzhiyun const char *from_name, const char *to_name,
2691*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
2692*4882a593Smuzhiyun {
2693*4882a593Smuzhiyun int rc = 0;
2694*4882a593Smuzhiyun RENAME_REQ *pSMB = NULL;
2695*4882a593Smuzhiyun RENAME_RSP *pSMBr = NULL;
2696*4882a593Smuzhiyun int bytes_returned;
2697*4882a593Smuzhiyun int name_len, name_len2;
2698*4882a593Smuzhiyun __u16 count;
2699*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
2700*4882a593Smuzhiyun
2701*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBRename\n");
2702*4882a593Smuzhiyun renameRetry:
2703*4882a593Smuzhiyun rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2704*4882a593Smuzhiyun (void **) &pSMBr);
2705*4882a593Smuzhiyun if (rc)
2706*4882a593Smuzhiyun return rc;
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
2709*4882a593Smuzhiyun pSMB->SearchAttributes =
2710*4882a593Smuzhiyun cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2711*4882a593Smuzhiyun ATTR_DIRECTORY);
2712*4882a593Smuzhiyun
2713*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2714*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2715*4882a593Smuzhiyun from_name, PATH_MAX,
2716*4882a593Smuzhiyun cifs_sb->local_nls, remap);
2717*4882a593Smuzhiyun name_len++; /* trailing null */
2718*4882a593Smuzhiyun name_len *= 2;
2719*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04; /* pad */
2720*4882a593Smuzhiyun /* protocol requires ASCII signature byte on Unicode string */
2721*4882a593Smuzhiyun pSMB->OldFileName[name_len + 1] = 0x00;
2722*4882a593Smuzhiyun name_len2 =
2723*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2724*4882a593Smuzhiyun to_name, PATH_MAX, cifs_sb->local_nls,
2725*4882a593Smuzhiyun remap);
2726*4882a593Smuzhiyun name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2727*4882a593Smuzhiyun name_len2 *= 2; /* convert to bytes */
2728*4882a593Smuzhiyun } else {
2729*4882a593Smuzhiyun name_len = copy_path_name(pSMB->OldFileName, from_name);
2730*4882a593Smuzhiyun name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
2731*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2732*4882a593Smuzhiyun name_len2++; /* signature byte */
2733*4882a593Smuzhiyun }
2734*4882a593Smuzhiyun
2735*4882a593Smuzhiyun count = 1 /* 1st signature byte */ + name_len + name_len2;
2736*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
2737*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
2738*4882a593Smuzhiyun
2739*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2740*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2741*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
2742*4882a593Smuzhiyun if (rc)
2743*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in rename = %d\n", rc);
2744*4882a593Smuzhiyun
2745*4882a593Smuzhiyun cifs_buf_release(pSMB);
2746*4882a593Smuzhiyun
2747*4882a593Smuzhiyun if (rc == -EAGAIN)
2748*4882a593Smuzhiyun goto renameRetry;
2749*4882a593Smuzhiyun
2750*4882a593Smuzhiyun return rc;
2751*4882a593Smuzhiyun }
2752*4882a593Smuzhiyun
CIFSSMBRenameOpenFile(const unsigned int xid,struct cifs_tcon * pTcon,int netfid,const char * target_name,const struct nls_table * nls_codepage,int remap)2753*4882a593Smuzhiyun int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
2754*4882a593Smuzhiyun int netfid, const char *target_name,
2755*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
2756*4882a593Smuzhiyun {
2757*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
2758*4882a593Smuzhiyun struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2759*4882a593Smuzhiyun struct set_file_rename *rename_info;
2760*4882a593Smuzhiyun char *data_offset;
2761*4882a593Smuzhiyun char dummy_string[30];
2762*4882a593Smuzhiyun int rc = 0;
2763*4882a593Smuzhiyun int bytes_returned = 0;
2764*4882a593Smuzhiyun int len_of_str;
2765*4882a593Smuzhiyun __u16 params, param_offset, offset, count, byte_count;
2766*4882a593Smuzhiyun
2767*4882a593Smuzhiyun cifs_dbg(FYI, "Rename to File by handle\n");
2768*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2769*4882a593Smuzhiyun (void **) &pSMBr);
2770*4882a593Smuzhiyun if (rc)
2771*4882a593Smuzhiyun return rc;
2772*4882a593Smuzhiyun
2773*4882a593Smuzhiyun params = 6;
2774*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
2775*4882a593Smuzhiyun pSMB->Reserved = 0;
2776*4882a593Smuzhiyun pSMB->Flags = 0;
2777*4882a593Smuzhiyun pSMB->Timeout = 0;
2778*4882a593Smuzhiyun pSMB->Reserved2 = 0;
2779*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2780*4882a593Smuzhiyun offset = param_offset + params;
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2783*4882a593Smuzhiyun rename_info = (struct set_file_rename *) data_offset;
2784*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
2785*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2786*4882a593Smuzhiyun pSMB->SetupCount = 1;
2787*4882a593Smuzhiyun pSMB->Reserved3 = 0;
2788*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2789*4882a593Smuzhiyun byte_count = 3 /* pad */ + params;
2790*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
2791*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
2792*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
2793*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
2794*4882a593Smuzhiyun /* construct random name ".cifs_tmp<inodenum><mid>" */
2795*4882a593Smuzhiyun rename_info->overwrite = cpu_to_le32(1);
2796*4882a593Smuzhiyun rename_info->root_fid = 0;
2797*4882a593Smuzhiyun /* unicode only call */
2798*4882a593Smuzhiyun if (target_name == NULL) {
2799*4882a593Smuzhiyun sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2800*4882a593Smuzhiyun len_of_str =
2801*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *)rename_info->target_name,
2802*4882a593Smuzhiyun dummy_string, 24, nls_codepage, remap);
2803*4882a593Smuzhiyun } else {
2804*4882a593Smuzhiyun len_of_str =
2805*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *)rename_info->target_name,
2806*4882a593Smuzhiyun target_name, PATH_MAX, nls_codepage,
2807*4882a593Smuzhiyun remap);
2808*4882a593Smuzhiyun }
2809*4882a593Smuzhiyun rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2810*4882a593Smuzhiyun count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
2811*4882a593Smuzhiyun byte_count += count;
2812*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
2813*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
2814*4882a593Smuzhiyun pSMB->Fid = netfid;
2815*4882a593Smuzhiyun pSMB->InformationLevel =
2816*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2817*4882a593Smuzhiyun pSMB->Reserved4 = 0;
2818*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
2819*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
2820*4882a593Smuzhiyun rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2821*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2822*4882a593Smuzhiyun cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
2823*4882a593Smuzhiyun if (rc)
2824*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2825*4882a593Smuzhiyun rc);
2826*4882a593Smuzhiyun
2827*4882a593Smuzhiyun cifs_buf_release(pSMB);
2828*4882a593Smuzhiyun
2829*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
2830*4882a593Smuzhiyun since file handle passed in no longer valid */
2831*4882a593Smuzhiyun
2832*4882a593Smuzhiyun return rc;
2833*4882a593Smuzhiyun }
2834*4882a593Smuzhiyun
2835*4882a593Smuzhiyun int
CIFSSMBCopy(const unsigned int xid,struct cifs_tcon * tcon,const char * fromName,const __u16 target_tid,const char * toName,const int flags,const struct nls_table * nls_codepage,int remap)2836*4882a593Smuzhiyun CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2837*4882a593Smuzhiyun const char *fromName, const __u16 target_tid, const char *toName,
2838*4882a593Smuzhiyun const int flags, const struct nls_table *nls_codepage, int remap)
2839*4882a593Smuzhiyun {
2840*4882a593Smuzhiyun int rc = 0;
2841*4882a593Smuzhiyun COPY_REQ *pSMB = NULL;
2842*4882a593Smuzhiyun COPY_RSP *pSMBr = NULL;
2843*4882a593Smuzhiyun int bytes_returned;
2844*4882a593Smuzhiyun int name_len, name_len2;
2845*4882a593Smuzhiyun __u16 count;
2846*4882a593Smuzhiyun
2847*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBCopy\n");
2848*4882a593Smuzhiyun copyRetry:
2849*4882a593Smuzhiyun rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2850*4882a593Smuzhiyun (void **) &pSMBr);
2851*4882a593Smuzhiyun if (rc)
2852*4882a593Smuzhiyun return rc;
2853*4882a593Smuzhiyun
2854*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
2855*4882a593Smuzhiyun pSMB->Tid2 = target_tid;
2856*4882a593Smuzhiyun
2857*4882a593Smuzhiyun pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2858*4882a593Smuzhiyun
2859*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2860*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2861*4882a593Smuzhiyun fromName, PATH_MAX, nls_codepage,
2862*4882a593Smuzhiyun remap);
2863*4882a593Smuzhiyun name_len++; /* trailing null */
2864*4882a593Smuzhiyun name_len *= 2;
2865*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04; /* pad */
2866*4882a593Smuzhiyun /* protocol requires ASCII signature byte on Unicode string */
2867*4882a593Smuzhiyun pSMB->OldFileName[name_len + 1] = 0x00;
2868*4882a593Smuzhiyun name_len2 =
2869*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2870*4882a593Smuzhiyun toName, PATH_MAX, nls_codepage, remap);
2871*4882a593Smuzhiyun name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2872*4882a593Smuzhiyun name_len2 *= 2; /* convert to bytes */
2873*4882a593Smuzhiyun } else {
2874*4882a593Smuzhiyun name_len = copy_path_name(pSMB->OldFileName, fromName);
2875*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2876*4882a593Smuzhiyun name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
2877*4882a593Smuzhiyun name_len2++; /* signature byte */
2878*4882a593Smuzhiyun }
2879*4882a593Smuzhiyun
2880*4882a593Smuzhiyun count = 1 /* 1st signature byte */ + name_len + name_len2;
2881*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
2882*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
2883*4882a593Smuzhiyun
2884*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2885*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2886*4882a593Smuzhiyun if (rc) {
2887*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2888*4882a593Smuzhiyun rc, le16_to_cpu(pSMBr->CopyCount));
2889*4882a593Smuzhiyun }
2890*4882a593Smuzhiyun cifs_buf_release(pSMB);
2891*4882a593Smuzhiyun
2892*4882a593Smuzhiyun if (rc == -EAGAIN)
2893*4882a593Smuzhiyun goto copyRetry;
2894*4882a593Smuzhiyun
2895*4882a593Smuzhiyun return rc;
2896*4882a593Smuzhiyun }
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun int
CIFSUnixCreateSymLink(const unsigned int xid,struct cifs_tcon * tcon,const char * fromName,const char * toName,const struct nls_table * nls_codepage,int remap)2899*4882a593Smuzhiyun CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
2900*4882a593Smuzhiyun const char *fromName, const char *toName,
2901*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
2902*4882a593Smuzhiyun {
2903*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
2904*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
2905*4882a593Smuzhiyun char *data_offset;
2906*4882a593Smuzhiyun int name_len;
2907*4882a593Smuzhiyun int name_len_target;
2908*4882a593Smuzhiyun int rc = 0;
2909*4882a593Smuzhiyun int bytes_returned = 0;
2910*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count;
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun cifs_dbg(FYI, "In Symlink Unix style\n");
2913*4882a593Smuzhiyun createSymLinkRetry:
2914*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2915*4882a593Smuzhiyun (void **) &pSMBr);
2916*4882a593Smuzhiyun if (rc)
2917*4882a593Smuzhiyun return rc;
2918*4882a593Smuzhiyun
2919*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2920*4882a593Smuzhiyun name_len =
2921*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2922*4882a593Smuzhiyun /* find define for this maxpathcomponent */
2923*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
2924*4882a593Smuzhiyun name_len++; /* trailing null */
2925*4882a593Smuzhiyun name_len *= 2;
2926*4882a593Smuzhiyun
2927*4882a593Smuzhiyun } else {
2928*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, fromName);
2929*4882a593Smuzhiyun }
2930*4882a593Smuzhiyun params = 6 + name_len;
2931*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
2932*4882a593Smuzhiyun pSMB->Reserved = 0;
2933*4882a593Smuzhiyun pSMB->Flags = 0;
2934*4882a593Smuzhiyun pSMB->Timeout = 0;
2935*4882a593Smuzhiyun pSMB->Reserved2 = 0;
2936*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
2937*4882a593Smuzhiyun InformationLevel) - 4;
2938*4882a593Smuzhiyun offset = param_offset + params;
2939*4882a593Smuzhiyun
2940*4882a593Smuzhiyun data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2941*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2942*4882a593Smuzhiyun name_len_target =
2943*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) data_offset, toName,
2944*4882a593Smuzhiyun /* find define for this maxpathcomponent */
2945*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
2946*4882a593Smuzhiyun name_len_target++; /* trailing null */
2947*4882a593Smuzhiyun name_len_target *= 2;
2948*4882a593Smuzhiyun } else {
2949*4882a593Smuzhiyun name_len_target = copy_path_name(data_offset, toName);
2950*4882a593Smuzhiyun }
2951*4882a593Smuzhiyun
2952*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
2953*4882a593Smuzhiyun /* BB find exact max on data count below from sess */
2954*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
2955*4882a593Smuzhiyun pSMB->SetupCount = 1;
2956*4882a593Smuzhiyun pSMB->Reserved3 = 0;
2957*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2958*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + name_len_target;
2959*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(name_len_target);
2960*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
2961*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
2962*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
2963*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
2964*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
2965*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2966*4882a593Smuzhiyun pSMB->Reserved4 = 0;
2967*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
2968*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
2969*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2970*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2971*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
2972*4882a593Smuzhiyun if (rc)
2973*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2974*4882a593Smuzhiyun rc);
2975*4882a593Smuzhiyun
2976*4882a593Smuzhiyun cifs_buf_release(pSMB);
2977*4882a593Smuzhiyun
2978*4882a593Smuzhiyun if (rc == -EAGAIN)
2979*4882a593Smuzhiyun goto createSymLinkRetry;
2980*4882a593Smuzhiyun
2981*4882a593Smuzhiyun return rc;
2982*4882a593Smuzhiyun }
2983*4882a593Smuzhiyun
2984*4882a593Smuzhiyun int
CIFSUnixCreateHardLink(const unsigned int xid,struct cifs_tcon * tcon,const char * fromName,const char * toName,const struct nls_table * nls_codepage,int remap)2985*4882a593Smuzhiyun CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2986*4882a593Smuzhiyun const char *fromName, const char *toName,
2987*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
2988*4882a593Smuzhiyun {
2989*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
2990*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
2991*4882a593Smuzhiyun char *data_offset;
2992*4882a593Smuzhiyun int name_len;
2993*4882a593Smuzhiyun int name_len_target;
2994*4882a593Smuzhiyun int rc = 0;
2995*4882a593Smuzhiyun int bytes_returned = 0;
2996*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count;
2997*4882a593Smuzhiyun
2998*4882a593Smuzhiyun cifs_dbg(FYI, "In Create Hard link Unix style\n");
2999*4882a593Smuzhiyun createHardLinkRetry:
3000*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3001*4882a593Smuzhiyun (void **) &pSMBr);
3002*4882a593Smuzhiyun if (rc)
3003*4882a593Smuzhiyun return rc;
3004*4882a593Smuzhiyun
3005*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3006*4882a593Smuzhiyun name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
3007*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
3008*4882a593Smuzhiyun name_len++; /* trailing null */
3009*4882a593Smuzhiyun name_len *= 2;
3010*4882a593Smuzhiyun
3011*4882a593Smuzhiyun } else {
3012*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, toName);
3013*4882a593Smuzhiyun }
3014*4882a593Smuzhiyun params = 6 + name_len;
3015*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3016*4882a593Smuzhiyun pSMB->Reserved = 0;
3017*4882a593Smuzhiyun pSMB->Flags = 0;
3018*4882a593Smuzhiyun pSMB->Timeout = 0;
3019*4882a593Smuzhiyun pSMB->Reserved2 = 0;
3020*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
3021*4882a593Smuzhiyun InformationLevel) - 4;
3022*4882a593Smuzhiyun offset = param_offset + params;
3023*4882a593Smuzhiyun
3024*4882a593Smuzhiyun data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3025*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3026*4882a593Smuzhiyun name_len_target =
3027*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) data_offset, fromName,
3028*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
3029*4882a593Smuzhiyun name_len_target++; /* trailing null */
3030*4882a593Smuzhiyun name_len_target *= 2;
3031*4882a593Smuzhiyun } else {
3032*4882a593Smuzhiyun name_len_target = copy_path_name(data_offset, fromName);
3033*4882a593Smuzhiyun }
3034*4882a593Smuzhiyun
3035*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
3036*4882a593Smuzhiyun /* BB find exact max on data count below from sess*/
3037*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
3038*4882a593Smuzhiyun pSMB->SetupCount = 1;
3039*4882a593Smuzhiyun pSMB->Reserved3 = 0;
3040*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3041*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + name_len_target;
3042*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
3043*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
3044*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(name_len_target);
3045*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
3046*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
3047*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
3048*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3049*4882a593Smuzhiyun pSMB->Reserved4 = 0;
3050*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
3051*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
3052*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3053*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3054*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
3055*4882a593Smuzhiyun if (rc)
3056*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3057*4882a593Smuzhiyun rc);
3058*4882a593Smuzhiyun
3059*4882a593Smuzhiyun cifs_buf_release(pSMB);
3060*4882a593Smuzhiyun if (rc == -EAGAIN)
3061*4882a593Smuzhiyun goto createHardLinkRetry;
3062*4882a593Smuzhiyun
3063*4882a593Smuzhiyun return rc;
3064*4882a593Smuzhiyun }
3065*4882a593Smuzhiyun
3066*4882a593Smuzhiyun int
CIFSCreateHardLink(const unsigned int xid,struct cifs_tcon * tcon,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)3067*4882a593Smuzhiyun CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
3068*4882a593Smuzhiyun const char *from_name, const char *to_name,
3069*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
3070*4882a593Smuzhiyun {
3071*4882a593Smuzhiyun int rc = 0;
3072*4882a593Smuzhiyun NT_RENAME_REQ *pSMB = NULL;
3073*4882a593Smuzhiyun RENAME_RSP *pSMBr = NULL;
3074*4882a593Smuzhiyun int bytes_returned;
3075*4882a593Smuzhiyun int name_len, name_len2;
3076*4882a593Smuzhiyun __u16 count;
3077*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
3078*4882a593Smuzhiyun
3079*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSCreateHardLink\n");
3080*4882a593Smuzhiyun winCreateHardLinkRetry:
3081*4882a593Smuzhiyun
3082*4882a593Smuzhiyun rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3083*4882a593Smuzhiyun (void **) &pSMBr);
3084*4882a593Smuzhiyun if (rc)
3085*4882a593Smuzhiyun return rc;
3086*4882a593Smuzhiyun
3087*4882a593Smuzhiyun pSMB->SearchAttributes =
3088*4882a593Smuzhiyun cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3089*4882a593Smuzhiyun ATTR_DIRECTORY);
3090*4882a593Smuzhiyun pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3091*4882a593Smuzhiyun pSMB->ClusterCount = 0;
3092*4882a593Smuzhiyun
3093*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
3094*4882a593Smuzhiyun
3095*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3096*4882a593Smuzhiyun name_len =
3097*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3098*4882a593Smuzhiyun PATH_MAX, cifs_sb->local_nls, remap);
3099*4882a593Smuzhiyun name_len++; /* trailing null */
3100*4882a593Smuzhiyun name_len *= 2;
3101*4882a593Smuzhiyun
3102*4882a593Smuzhiyun /* protocol specifies ASCII buffer format (0x04) for unicode */
3103*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04;
3104*4882a593Smuzhiyun pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
3105*4882a593Smuzhiyun name_len2 =
3106*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
3107*4882a593Smuzhiyun to_name, PATH_MAX, cifs_sb->local_nls,
3108*4882a593Smuzhiyun remap);
3109*4882a593Smuzhiyun name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3110*4882a593Smuzhiyun name_len2 *= 2; /* convert to bytes */
3111*4882a593Smuzhiyun } else {
3112*4882a593Smuzhiyun name_len = copy_path_name(pSMB->OldFileName, from_name);
3113*4882a593Smuzhiyun pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
3114*4882a593Smuzhiyun name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
3115*4882a593Smuzhiyun name_len2++; /* signature byte */
3116*4882a593Smuzhiyun }
3117*4882a593Smuzhiyun
3118*4882a593Smuzhiyun count = 1 /* string type byte */ + name_len + name_len2;
3119*4882a593Smuzhiyun inc_rfc1001_len(pSMB, count);
3120*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
3121*4882a593Smuzhiyun
3122*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3123*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3124*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
3125*4882a593Smuzhiyun if (rc)
3126*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
3127*4882a593Smuzhiyun
3128*4882a593Smuzhiyun cifs_buf_release(pSMB);
3129*4882a593Smuzhiyun if (rc == -EAGAIN)
3130*4882a593Smuzhiyun goto winCreateHardLinkRetry;
3131*4882a593Smuzhiyun
3132*4882a593Smuzhiyun return rc;
3133*4882a593Smuzhiyun }
3134*4882a593Smuzhiyun
3135*4882a593Smuzhiyun int
CIFSSMBUnixQuerySymLink(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,char ** symlinkinfo,const struct nls_table * nls_codepage,int remap)3136*4882a593Smuzhiyun CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3137*4882a593Smuzhiyun const unsigned char *searchName, char **symlinkinfo,
3138*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
3139*4882a593Smuzhiyun {
3140*4882a593Smuzhiyun /* SMB_QUERY_FILE_UNIX_LINK */
3141*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
3142*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
3143*4882a593Smuzhiyun int rc = 0;
3144*4882a593Smuzhiyun int bytes_returned;
3145*4882a593Smuzhiyun int name_len;
3146*4882a593Smuzhiyun __u16 params, byte_count;
3147*4882a593Smuzhiyun char *data_start;
3148*4882a593Smuzhiyun
3149*4882a593Smuzhiyun cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
3150*4882a593Smuzhiyun
3151*4882a593Smuzhiyun querySymLinkRetry:
3152*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3153*4882a593Smuzhiyun (void **) &pSMBr);
3154*4882a593Smuzhiyun if (rc)
3155*4882a593Smuzhiyun return rc;
3156*4882a593Smuzhiyun
3157*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3158*4882a593Smuzhiyun name_len =
3159*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName,
3160*4882a593Smuzhiyun searchName, PATH_MAX, nls_codepage,
3161*4882a593Smuzhiyun remap);
3162*4882a593Smuzhiyun name_len++; /* trailing null */
3163*4882a593Smuzhiyun name_len *= 2;
3164*4882a593Smuzhiyun } else {
3165*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, searchName);
3166*4882a593Smuzhiyun }
3167*4882a593Smuzhiyun
3168*4882a593Smuzhiyun params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3169*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
3170*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
3171*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3172*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3173*4882a593Smuzhiyun pSMB->Reserved = 0;
3174*4882a593Smuzhiyun pSMB->Flags = 0;
3175*4882a593Smuzhiyun pSMB->Timeout = 0;
3176*4882a593Smuzhiyun pSMB->Reserved2 = 0;
3177*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
3178*4882a593Smuzhiyun struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3179*4882a593Smuzhiyun pSMB->DataCount = 0;
3180*4882a593Smuzhiyun pSMB->DataOffset = 0;
3181*4882a593Smuzhiyun pSMB->SetupCount = 1;
3182*4882a593Smuzhiyun pSMB->Reserved3 = 0;
3183*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3184*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
3185*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
3186*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
3187*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3188*4882a593Smuzhiyun pSMB->Reserved4 = 0;
3189*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
3190*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
3191*4882a593Smuzhiyun
3192*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3193*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3194*4882a593Smuzhiyun if (rc) {
3195*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
3196*4882a593Smuzhiyun } else {
3197*4882a593Smuzhiyun /* decode response */
3198*4882a593Smuzhiyun
3199*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3200*4882a593Smuzhiyun /* BB also check enough total bytes returned */
3201*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 2)
3202*4882a593Smuzhiyun rc = -EIO;
3203*4882a593Smuzhiyun else {
3204*4882a593Smuzhiyun bool is_unicode;
3205*4882a593Smuzhiyun u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3206*4882a593Smuzhiyun
3207*4882a593Smuzhiyun data_start = ((char *) &pSMBr->hdr.Protocol) +
3208*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.DataOffset);
3209*4882a593Smuzhiyun
3210*4882a593Smuzhiyun if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3211*4882a593Smuzhiyun is_unicode = true;
3212*4882a593Smuzhiyun else
3213*4882a593Smuzhiyun is_unicode = false;
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun /* BB FIXME investigate remapping reserved chars here */
3216*4882a593Smuzhiyun *symlinkinfo = cifs_strndup_from_utf16(data_start,
3217*4882a593Smuzhiyun count, is_unicode, nls_codepage);
3218*4882a593Smuzhiyun if (!*symlinkinfo)
3219*4882a593Smuzhiyun rc = -ENOMEM;
3220*4882a593Smuzhiyun }
3221*4882a593Smuzhiyun }
3222*4882a593Smuzhiyun cifs_buf_release(pSMB);
3223*4882a593Smuzhiyun if (rc == -EAGAIN)
3224*4882a593Smuzhiyun goto querySymLinkRetry;
3225*4882a593Smuzhiyun return rc;
3226*4882a593Smuzhiyun }
3227*4882a593Smuzhiyun
3228*4882a593Smuzhiyun /*
3229*4882a593Smuzhiyun * Recent Windows versions now create symlinks more frequently
3230*4882a593Smuzhiyun * and they use the "reparse point" mechanism below. We can of course
3231*4882a593Smuzhiyun * do symlinks nicely to Samba and other servers which support the
3232*4882a593Smuzhiyun * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3233*4882a593Smuzhiyun * "MF" symlinks optionally, but for recent Windows we really need to
3234*4882a593Smuzhiyun * reenable the code below and fix the cifs_symlink callers to handle this.
3235*4882a593Smuzhiyun * In the interim this code has been moved to its own config option so
3236*4882a593Smuzhiyun * it is not compiled in by default until callers fixed up and more tested.
3237*4882a593Smuzhiyun */
3238*4882a593Smuzhiyun int
CIFSSMBQuerySymLink(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid,char ** symlinkinfo,const struct nls_table * nls_codepage)3239*4882a593Smuzhiyun CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3240*4882a593Smuzhiyun __u16 fid, char **symlinkinfo,
3241*4882a593Smuzhiyun const struct nls_table *nls_codepage)
3242*4882a593Smuzhiyun {
3243*4882a593Smuzhiyun int rc = 0;
3244*4882a593Smuzhiyun int bytes_returned;
3245*4882a593Smuzhiyun struct smb_com_transaction_ioctl_req *pSMB;
3246*4882a593Smuzhiyun struct smb_com_transaction_ioctl_rsp *pSMBr;
3247*4882a593Smuzhiyun bool is_unicode;
3248*4882a593Smuzhiyun unsigned int sub_len;
3249*4882a593Smuzhiyun char *sub_start;
3250*4882a593Smuzhiyun struct reparse_symlink_data *reparse_buf;
3251*4882a593Smuzhiyun struct reparse_posix_data *posix_buf;
3252*4882a593Smuzhiyun __u32 data_offset, data_count;
3253*4882a593Smuzhiyun char *end_of_smb;
3254*4882a593Smuzhiyun
3255*4882a593Smuzhiyun cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
3256*4882a593Smuzhiyun rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3257*4882a593Smuzhiyun (void **) &pSMBr);
3258*4882a593Smuzhiyun if (rc)
3259*4882a593Smuzhiyun return rc;
3260*4882a593Smuzhiyun
3261*4882a593Smuzhiyun pSMB->TotalParameterCount = 0 ;
3262*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
3263*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le32(2);
3264*4882a593Smuzhiyun /* BB find exact data count max from sess structure BB */
3265*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3266*4882a593Smuzhiyun pSMB->MaxSetupCount = 4;
3267*4882a593Smuzhiyun pSMB->Reserved = 0;
3268*4882a593Smuzhiyun pSMB->ParameterOffset = 0;
3269*4882a593Smuzhiyun pSMB->DataCount = 0;
3270*4882a593Smuzhiyun pSMB->DataOffset = 0;
3271*4882a593Smuzhiyun pSMB->SetupCount = 4;
3272*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3273*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
3274*4882a593Smuzhiyun pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3275*4882a593Smuzhiyun pSMB->IsFsctl = 1; /* FSCTL */
3276*4882a593Smuzhiyun pSMB->IsRootFlag = 0;
3277*4882a593Smuzhiyun pSMB->Fid = fid; /* file handle always le */
3278*4882a593Smuzhiyun pSMB->ByteCount = 0;
3279*4882a593Smuzhiyun
3280*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3281*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3282*4882a593Smuzhiyun if (rc) {
3283*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3284*4882a593Smuzhiyun goto qreparse_out;
3285*4882a593Smuzhiyun }
3286*4882a593Smuzhiyun
3287*4882a593Smuzhiyun data_offset = le32_to_cpu(pSMBr->DataOffset);
3288*4882a593Smuzhiyun data_count = le32_to_cpu(pSMBr->DataCount);
3289*4882a593Smuzhiyun if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3290*4882a593Smuzhiyun /* BB also check enough total bytes returned */
3291*4882a593Smuzhiyun rc = -EIO; /* bad smb */
3292*4882a593Smuzhiyun goto qreparse_out;
3293*4882a593Smuzhiyun }
3294*4882a593Smuzhiyun if (!data_count || (data_count > 2048)) {
3295*4882a593Smuzhiyun rc = -EIO;
3296*4882a593Smuzhiyun cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3297*4882a593Smuzhiyun goto qreparse_out;
3298*4882a593Smuzhiyun }
3299*4882a593Smuzhiyun end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3300*4882a593Smuzhiyun reparse_buf = (struct reparse_symlink_data *)
3301*4882a593Smuzhiyun ((char *)&pSMBr->hdr.Protocol + data_offset);
3302*4882a593Smuzhiyun if ((char *)reparse_buf >= end_of_smb) {
3303*4882a593Smuzhiyun rc = -EIO;
3304*4882a593Smuzhiyun goto qreparse_out;
3305*4882a593Smuzhiyun }
3306*4882a593Smuzhiyun if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3307*4882a593Smuzhiyun cifs_dbg(FYI, "NFS style reparse tag\n");
3308*4882a593Smuzhiyun posix_buf = (struct reparse_posix_data *)reparse_buf;
3309*4882a593Smuzhiyun
3310*4882a593Smuzhiyun if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3311*4882a593Smuzhiyun cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3312*4882a593Smuzhiyun le64_to_cpu(posix_buf->InodeType));
3313*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3314*4882a593Smuzhiyun goto qreparse_out;
3315*4882a593Smuzhiyun }
3316*4882a593Smuzhiyun is_unicode = true;
3317*4882a593Smuzhiyun sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3318*4882a593Smuzhiyun if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3319*4882a593Smuzhiyun cifs_dbg(FYI, "reparse buf beyond SMB\n");
3320*4882a593Smuzhiyun rc = -EIO;
3321*4882a593Smuzhiyun goto qreparse_out;
3322*4882a593Smuzhiyun }
3323*4882a593Smuzhiyun *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3324*4882a593Smuzhiyun sub_len, is_unicode, nls_codepage);
3325*4882a593Smuzhiyun goto qreparse_out;
3326*4882a593Smuzhiyun } else if (reparse_buf->ReparseTag !=
3327*4882a593Smuzhiyun cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3328*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3329*4882a593Smuzhiyun goto qreparse_out;
3330*4882a593Smuzhiyun }
3331*4882a593Smuzhiyun
3332*4882a593Smuzhiyun /* Reparse tag is NTFS symlink */
3333*4882a593Smuzhiyun sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3334*4882a593Smuzhiyun reparse_buf->PathBuffer;
3335*4882a593Smuzhiyun sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3336*4882a593Smuzhiyun if (sub_start + sub_len > end_of_smb) {
3337*4882a593Smuzhiyun cifs_dbg(FYI, "reparse buf beyond SMB\n");
3338*4882a593Smuzhiyun rc = -EIO;
3339*4882a593Smuzhiyun goto qreparse_out;
3340*4882a593Smuzhiyun }
3341*4882a593Smuzhiyun if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3342*4882a593Smuzhiyun is_unicode = true;
3343*4882a593Smuzhiyun else
3344*4882a593Smuzhiyun is_unicode = false;
3345*4882a593Smuzhiyun
3346*4882a593Smuzhiyun /* BB FIXME investigate remapping reserved chars here */
3347*4882a593Smuzhiyun *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3348*4882a593Smuzhiyun nls_codepage);
3349*4882a593Smuzhiyun if (!*symlinkinfo)
3350*4882a593Smuzhiyun rc = -ENOMEM;
3351*4882a593Smuzhiyun qreparse_out:
3352*4882a593Smuzhiyun cifs_buf_release(pSMB);
3353*4882a593Smuzhiyun
3354*4882a593Smuzhiyun /*
3355*4882a593Smuzhiyun * Note: On -EAGAIN error only caller can retry on handle based calls
3356*4882a593Smuzhiyun * since file handle passed in no longer valid.
3357*4882a593Smuzhiyun */
3358*4882a593Smuzhiyun return rc;
3359*4882a593Smuzhiyun }
3360*4882a593Smuzhiyun
3361*4882a593Smuzhiyun int
CIFSSMB_set_compression(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid)3362*4882a593Smuzhiyun CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3363*4882a593Smuzhiyun __u16 fid)
3364*4882a593Smuzhiyun {
3365*4882a593Smuzhiyun int rc = 0;
3366*4882a593Smuzhiyun int bytes_returned;
3367*4882a593Smuzhiyun struct smb_com_transaction_compr_ioctl_req *pSMB;
3368*4882a593Smuzhiyun struct smb_com_transaction_ioctl_rsp *pSMBr;
3369*4882a593Smuzhiyun
3370*4882a593Smuzhiyun cifs_dbg(FYI, "Set compression for %u\n", fid);
3371*4882a593Smuzhiyun rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3372*4882a593Smuzhiyun (void **) &pSMBr);
3373*4882a593Smuzhiyun if (rc)
3374*4882a593Smuzhiyun return rc;
3375*4882a593Smuzhiyun
3376*4882a593Smuzhiyun pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3377*4882a593Smuzhiyun
3378*4882a593Smuzhiyun pSMB->TotalParameterCount = 0;
3379*4882a593Smuzhiyun pSMB->TotalDataCount = cpu_to_le32(2);
3380*4882a593Smuzhiyun pSMB->MaxParameterCount = 0;
3381*4882a593Smuzhiyun pSMB->MaxDataCount = 0;
3382*4882a593Smuzhiyun pSMB->MaxSetupCount = 4;
3383*4882a593Smuzhiyun pSMB->Reserved = 0;
3384*4882a593Smuzhiyun pSMB->ParameterOffset = 0;
3385*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le32(2);
3386*4882a593Smuzhiyun pSMB->DataOffset =
3387*4882a593Smuzhiyun cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3388*4882a593Smuzhiyun compression_state) - 4); /* 84 */
3389*4882a593Smuzhiyun pSMB->SetupCount = 4;
3390*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3391*4882a593Smuzhiyun pSMB->ParameterCount = 0;
3392*4882a593Smuzhiyun pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
3393*4882a593Smuzhiyun pSMB->IsFsctl = 1; /* FSCTL */
3394*4882a593Smuzhiyun pSMB->IsRootFlag = 0;
3395*4882a593Smuzhiyun pSMB->Fid = fid; /* file handle always le */
3396*4882a593Smuzhiyun /* 3 byte pad, followed by 2 byte compress state */
3397*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(5);
3398*4882a593Smuzhiyun inc_rfc1001_len(pSMB, 5);
3399*4882a593Smuzhiyun
3400*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3401*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3402*4882a593Smuzhiyun if (rc)
3403*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3404*4882a593Smuzhiyun
3405*4882a593Smuzhiyun cifs_buf_release(pSMB);
3406*4882a593Smuzhiyun
3407*4882a593Smuzhiyun /*
3408*4882a593Smuzhiyun * Note: On -EAGAIN error only caller can retry on handle based calls
3409*4882a593Smuzhiyun * since file handle passed in no longer valid.
3410*4882a593Smuzhiyun */
3411*4882a593Smuzhiyun return rc;
3412*4882a593Smuzhiyun }
3413*4882a593Smuzhiyun
3414*4882a593Smuzhiyun
3415*4882a593Smuzhiyun #ifdef CONFIG_CIFS_POSIX
3416*4882a593Smuzhiyun
3417*4882a593Smuzhiyun /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
cifs_convert_ace(struct posix_acl_xattr_entry * ace,struct cifs_posix_ace * cifs_ace)3418*4882a593Smuzhiyun static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
3419*4882a593Smuzhiyun struct cifs_posix_ace *cifs_ace)
3420*4882a593Smuzhiyun {
3421*4882a593Smuzhiyun /* u8 cifs fields do not need le conversion */
3422*4882a593Smuzhiyun ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3423*4882a593Smuzhiyun ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3424*4882a593Smuzhiyun ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3425*4882a593Smuzhiyun /*
3426*4882a593Smuzhiyun cifs_dbg(FYI, "perm %d tag %d id %d\n",
3427*4882a593Smuzhiyun ace->e_perm, ace->e_tag, ace->e_id);
3428*4882a593Smuzhiyun */
3429*4882a593Smuzhiyun
3430*4882a593Smuzhiyun return;
3431*4882a593Smuzhiyun }
3432*4882a593Smuzhiyun
3433*4882a593Smuzhiyun /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
cifs_copy_posix_acl(char * trgt,char * src,const int buflen,const int acl_type,const int size_of_data_area)3434*4882a593Smuzhiyun static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3435*4882a593Smuzhiyun const int acl_type, const int size_of_data_area)
3436*4882a593Smuzhiyun {
3437*4882a593Smuzhiyun int size = 0;
3438*4882a593Smuzhiyun int i;
3439*4882a593Smuzhiyun __u16 count;
3440*4882a593Smuzhiyun struct cifs_posix_ace *pACE;
3441*4882a593Smuzhiyun struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3442*4882a593Smuzhiyun struct posix_acl_xattr_header *local_acl = (void *)trgt;
3443*4882a593Smuzhiyun
3444*4882a593Smuzhiyun if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3445*4882a593Smuzhiyun return -EOPNOTSUPP;
3446*4882a593Smuzhiyun
3447*4882a593Smuzhiyun if (acl_type == ACL_TYPE_ACCESS) {
3448*4882a593Smuzhiyun count = le16_to_cpu(cifs_acl->access_entry_count);
3449*4882a593Smuzhiyun pACE = &cifs_acl->ace_array[0];
3450*4882a593Smuzhiyun size = sizeof(struct cifs_posix_acl);
3451*4882a593Smuzhiyun size += sizeof(struct cifs_posix_ace) * count;
3452*4882a593Smuzhiyun /* check if we would go beyond end of SMB */
3453*4882a593Smuzhiyun if (size_of_data_area < size) {
3454*4882a593Smuzhiyun cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3455*4882a593Smuzhiyun size_of_data_area, size);
3456*4882a593Smuzhiyun return -EINVAL;
3457*4882a593Smuzhiyun }
3458*4882a593Smuzhiyun } else if (acl_type == ACL_TYPE_DEFAULT) {
3459*4882a593Smuzhiyun count = le16_to_cpu(cifs_acl->access_entry_count);
3460*4882a593Smuzhiyun size = sizeof(struct cifs_posix_acl);
3461*4882a593Smuzhiyun size += sizeof(struct cifs_posix_ace) * count;
3462*4882a593Smuzhiyun /* skip past access ACEs to get to default ACEs */
3463*4882a593Smuzhiyun pACE = &cifs_acl->ace_array[count];
3464*4882a593Smuzhiyun count = le16_to_cpu(cifs_acl->default_entry_count);
3465*4882a593Smuzhiyun size += sizeof(struct cifs_posix_ace) * count;
3466*4882a593Smuzhiyun /* check if we would go beyond end of SMB */
3467*4882a593Smuzhiyun if (size_of_data_area < size)
3468*4882a593Smuzhiyun return -EINVAL;
3469*4882a593Smuzhiyun } else {
3470*4882a593Smuzhiyun /* illegal type */
3471*4882a593Smuzhiyun return -EINVAL;
3472*4882a593Smuzhiyun }
3473*4882a593Smuzhiyun
3474*4882a593Smuzhiyun size = posix_acl_xattr_size(count);
3475*4882a593Smuzhiyun if ((buflen == 0) || (local_acl == NULL)) {
3476*4882a593Smuzhiyun /* used to query ACL EA size */
3477*4882a593Smuzhiyun } else if (size > buflen) {
3478*4882a593Smuzhiyun return -ERANGE;
3479*4882a593Smuzhiyun } else /* buffer big enough */ {
3480*4882a593Smuzhiyun struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3481*4882a593Smuzhiyun
3482*4882a593Smuzhiyun local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3483*4882a593Smuzhiyun for (i = 0; i < count ; i++) {
3484*4882a593Smuzhiyun cifs_convert_ace(&ace[i], pACE);
3485*4882a593Smuzhiyun pACE++;
3486*4882a593Smuzhiyun }
3487*4882a593Smuzhiyun }
3488*4882a593Smuzhiyun return size;
3489*4882a593Smuzhiyun }
3490*4882a593Smuzhiyun
convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,const struct posix_acl_xattr_entry * local_ace)3491*4882a593Smuzhiyun static void convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3492*4882a593Smuzhiyun const struct posix_acl_xattr_entry *local_ace)
3493*4882a593Smuzhiyun {
3494*4882a593Smuzhiyun cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3495*4882a593Smuzhiyun cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
3496*4882a593Smuzhiyun /* BB is there a better way to handle the large uid? */
3497*4882a593Smuzhiyun if (local_ace->e_id == cpu_to_le32(-1)) {
3498*4882a593Smuzhiyun /* Probably no need to le convert -1 on any arch but can not hurt */
3499*4882a593Smuzhiyun cifs_ace->cifs_uid = cpu_to_le64(-1);
3500*4882a593Smuzhiyun } else
3501*4882a593Smuzhiyun cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3502*4882a593Smuzhiyun /*
3503*4882a593Smuzhiyun cifs_dbg(FYI, "perm %d tag %d id %d\n",
3504*4882a593Smuzhiyun ace->e_perm, ace->e_tag, ace->e_id);
3505*4882a593Smuzhiyun */
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun
3508*4882a593Smuzhiyun /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,const int acl_type)3509*4882a593Smuzhiyun static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3510*4882a593Smuzhiyun const int buflen, const int acl_type)
3511*4882a593Smuzhiyun {
3512*4882a593Smuzhiyun __u16 rc = 0;
3513*4882a593Smuzhiyun struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3514*4882a593Smuzhiyun struct posix_acl_xattr_header *local_acl = (void *)pACL;
3515*4882a593Smuzhiyun struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3516*4882a593Smuzhiyun int count;
3517*4882a593Smuzhiyun int i;
3518*4882a593Smuzhiyun
3519*4882a593Smuzhiyun if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
3520*4882a593Smuzhiyun return 0;
3521*4882a593Smuzhiyun
3522*4882a593Smuzhiyun count = posix_acl_xattr_count((size_t)buflen);
3523*4882a593Smuzhiyun cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3524*4882a593Smuzhiyun count, buflen, le32_to_cpu(local_acl->a_version));
3525*4882a593Smuzhiyun if (le32_to_cpu(local_acl->a_version) != 2) {
3526*4882a593Smuzhiyun cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3527*4882a593Smuzhiyun le32_to_cpu(local_acl->a_version));
3528*4882a593Smuzhiyun return 0;
3529*4882a593Smuzhiyun }
3530*4882a593Smuzhiyun cifs_acl->version = cpu_to_le16(1);
3531*4882a593Smuzhiyun if (acl_type == ACL_TYPE_ACCESS) {
3532*4882a593Smuzhiyun cifs_acl->access_entry_count = cpu_to_le16(count);
3533*4882a593Smuzhiyun cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
3534*4882a593Smuzhiyun } else if (acl_type == ACL_TYPE_DEFAULT) {
3535*4882a593Smuzhiyun cifs_acl->default_entry_count = cpu_to_le16(count);
3536*4882a593Smuzhiyun cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
3537*4882a593Smuzhiyun } else {
3538*4882a593Smuzhiyun cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
3539*4882a593Smuzhiyun return 0;
3540*4882a593Smuzhiyun }
3541*4882a593Smuzhiyun for (i = 0; i < count; i++)
3542*4882a593Smuzhiyun convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
3543*4882a593Smuzhiyun if (rc == 0) {
3544*4882a593Smuzhiyun rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3545*4882a593Smuzhiyun rc += sizeof(struct cifs_posix_acl);
3546*4882a593Smuzhiyun /* BB add check to make sure ACL does not overflow SMB */
3547*4882a593Smuzhiyun }
3548*4882a593Smuzhiyun return rc;
3549*4882a593Smuzhiyun }
3550*4882a593Smuzhiyun
3551*4882a593Smuzhiyun int
CIFSSMBGetPosixACL(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,char * acl_inf,const int buflen,const int acl_type,const struct nls_table * nls_codepage,int remap)3552*4882a593Smuzhiyun CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3553*4882a593Smuzhiyun const unsigned char *searchName,
3554*4882a593Smuzhiyun char *acl_inf, const int buflen, const int acl_type,
3555*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
3556*4882a593Smuzhiyun {
3557*4882a593Smuzhiyun /* SMB_QUERY_POSIX_ACL */
3558*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
3559*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
3560*4882a593Smuzhiyun int rc = 0;
3561*4882a593Smuzhiyun int bytes_returned;
3562*4882a593Smuzhiyun int name_len;
3563*4882a593Smuzhiyun __u16 params, byte_count;
3564*4882a593Smuzhiyun
3565*4882a593Smuzhiyun cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
3566*4882a593Smuzhiyun
3567*4882a593Smuzhiyun queryAclRetry:
3568*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3569*4882a593Smuzhiyun (void **) &pSMBr);
3570*4882a593Smuzhiyun if (rc)
3571*4882a593Smuzhiyun return rc;
3572*4882a593Smuzhiyun
3573*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3574*4882a593Smuzhiyun name_len =
3575*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName,
3576*4882a593Smuzhiyun searchName, PATH_MAX, nls_codepage,
3577*4882a593Smuzhiyun remap);
3578*4882a593Smuzhiyun name_len++; /* trailing null */
3579*4882a593Smuzhiyun name_len *= 2;
3580*4882a593Smuzhiyun pSMB->FileName[name_len] = 0;
3581*4882a593Smuzhiyun pSMB->FileName[name_len+1] = 0;
3582*4882a593Smuzhiyun } else {
3583*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, searchName);
3584*4882a593Smuzhiyun }
3585*4882a593Smuzhiyun
3586*4882a593Smuzhiyun params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3587*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
3588*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
3589*4882a593Smuzhiyun /* BB find exact max data count below from sess structure BB */
3590*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4000);
3591*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3592*4882a593Smuzhiyun pSMB->Reserved = 0;
3593*4882a593Smuzhiyun pSMB->Flags = 0;
3594*4882a593Smuzhiyun pSMB->Timeout = 0;
3595*4882a593Smuzhiyun pSMB->Reserved2 = 0;
3596*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(
3597*4882a593Smuzhiyun offsetof(struct smb_com_transaction2_qpi_req,
3598*4882a593Smuzhiyun InformationLevel) - 4);
3599*4882a593Smuzhiyun pSMB->DataCount = 0;
3600*4882a593Smuzhiyun pSMB->DataOffset = 0;
3601*4882a593Smuzhiyun pSMB->SetupCount = 1;
3602*4882a593Smuzhiyun pSMB->Reserved3 = 0;
3603*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3604*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
3605*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
3606*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
3607*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3608*4882a593Smuzhiyun pSMB->Reserved4 = 0;
3609*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
3610*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
3611*4882a593Smuzhiyun
3612*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3613*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3614*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3615*4882a593Smuzhiyun if (rc) {
3616*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
3617*4882a593Smuzhiyun } else {
3618*4882a593Smuzhiyun /* decode response */
3619*4882a593Smuzhiyun
3620*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3621*4882a593Smuzhiyun /* BB also check enough total bytes returned */
3622*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 2)
3623*4882a593Smuzhiyun rc = -EIO; /* bad smb */
3624*4882a593Smuzhiyun else {
3625*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3626*4882a593Smuzhiyun __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3627*4882a593Smuzhiyun rc = cifs_copy_posix_acl(acl_inf,
3628*4882a593Smuzhiyun (char *)&pSMBr->hdr.Protocol+data_offset,
3629*4882a593Smuzhiyun buflen, acl_type, count);
3630*4882a593Smuzhiyun }
3631*4882a593Smuzhiyun }
3632*4882a593Smuzhiyun cifs_buf_release(pSMB);
3633*4882a593Smuzhiyun if (rc == -EAGAIN)
3634*4882a593Smuzhiyun goto queryAclRetry;
3635*4882a593Smuzhiyun return rc;
3636*4882a593Smuzhiyun }
3637*4882a593Smuzhiyun
3638*4882a593Smuzhiyun int
CIFSSMBSetPosixACL(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * fileName,const char * local_acl,const int buflen,const int acl_type,const struct nls_table * nls_codepage,int remap)3639*4882a593Smuzhiyun CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3640*4882a593Smuzhiyun const unsigned char *fileName,
3641*4882a593Smuzhiyun const char *local_acl, const int buflen,
3642*4882a593Smuzhiyun const int acl_type,
3643*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
3644*4882a593Smuzhiyun {
3645*4882a593Smuzhiyun struct smb_com_transaction2_spi_req *pSMB = NULL;
3646*4882a593Smuzhiyun struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3647*4882a593Smuzhiyun char *parm_data;
3648*4882a593Smuzhiyun int name_len;
3649*4882a593Smuzhiyun int rc = 0;
3650*4882a593Smuzhiyun int bytes_returned = 0;
3651*4882a593Smuzhiyun __u16 params, byte_count, data_count, param_offset, offset;
3652*4882a593Smuzhiyun
3653*4882a593Smuzhiyun cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
3654*4882a593Smuzhiyun setAclRetry:
3655*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3656*4882a593Smuzhiyun (void **) &pSMBr);
3657*4882a593Smuzhiyun if (rc)
3658*4882a593Smuzhiyun return rc;
3659*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3660*4882a593Smuzhiyun name_len =
3661*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3662*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
3663*4882a593Smuzhiyun name_len++; /* trailing null */
3664*4882a593Smuzhiyun name_len *= 2;
3665*4882a593Smuzhiyun } else {
3666*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, fileName);
3667*4882a593Smuzhiyun }
3668*4882a593Smuzhiyun params = 6 + name_len;
3669*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
3670*4882a593Smuzhiyun /* BB find max SMB size from sess */
3671*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
3672*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3673*4882a593Smuzhiyun pSMB->Reserved = 0;
3674*4882a593Smuzhiyun pSMB->Flags = 0;
3675*4882a593Smuzhiyun pSMB->Timeout = 0;
3676*4882a593Smuzhiyun pSMB->Reserved2 = 0;
3677*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
3678*4882a593Smuzhiyun InformationLevel) - 4;
3679*4882a593Smuzhiyun offset = param_offset + params;
3680*4882a593Smuzhiyun parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3681*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
3682*4882a593Smuzhiyun
3683*4882a593Smuzhiyun /* convert to on the wire format for POSIX ACL */
3684*4882a593Smuzhiyun data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
3685*4882a593Smuzhiyun
3686*4882a593Smuzhiyun if (data_count == 0) {
3687*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3688*4882a593Smuzhiyun goto setACLerrorExit;
3689*4882a593Smuzhiyun }
3690*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
3691*4882a593Smuzhiyun pSMB->SetupCount = 1;
3692*4882a593Smuzhiyun pSMB->Reserved3 = 0;
3693*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3694*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3695*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + data_count;
3696*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(data_count);
3697*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
3698*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
3699*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
3700*4882a593Smuzhiyun pSMB->Reserved4 = 0;
3701*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
3702*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
3703*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3704*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3705*4882a593Smuzhiyun if (rc)
3706*4882a593Smuzhiyun cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
3707*4882a593Smuzhiyun
3708*4882a593Smuzhiyun setACLerrorExit:
3709*4882a593Smuzhiyun cifs_buf_release(pSMB);
3710*4882a593Smuzhiyun if (rc == -EAGAIN)
3711*4882a593Smuzhiyun goto setAclRetry;
3712*4882a593Smuzhiyun return rc;
3713*4882a593Smuzhiyun }
3714*4882a593Smuzhiyun
3715*4882a593Smuzhiyun /* BB fix tabs in this function FIXME BB */
3716*4882a593Smuzhiyun int
CIFSGetExtAttr(const unsigned int xid,struct cifs_tcon * tcon,const int netfid,__u64 * pExtAttrBits,__u64 * pMask)3717*4882a593Smuzhiyun CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
3718*4882a593Smuzhiyun const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3719*4882a593Smuzhiyun {
3720*4882a593Smuzhiyun int rc = 0;
3721*4882a593Smuzhiyun struct smb_t2_qfi_req *pSMB = NULL;
3722*4882a593Smuzhiyun struct smb_t2_qfi_rsp *pSMBr = NULL;
3723*4882a593Smuzhiyun int bytes_returned;
3724*4882a593Smuzhiyun __u16 params, byte_count;
3725*4882a593Smuzhiyun
3726*4882a593Smuzhiyun cifs_dbg(FYI, "In GetExtAttr\n");
3727*4882a593Smuzhiyun if (tcon == NULL)
3728*4882a593Smuzhiyun return -ENODEV;
3729*4882a593Smuzhiyun
3730*4882a593Smuzhiyun GetExtAttrRetry:
3731*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3732*4882a593Smuzhiyun (void **) &pSMBr);
3733*4882a593Smuzhiyun if (rc)
3734*4882a593Smuzhiyun return rc;
3735*4882a593Smuzhiyun
3736*4882a593Smuzhiyun params = 2 /* level */ + 2 /* fid */;
3737*4882a593Smuzhiyun pSMB->t2.TotalDataCount = 0;
3738*4882a593Smuzhiyun pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3739*4882a593Smuzhiyun /* BB find exact max data count below from sess structure BB */
3740*4882a593Smuzhiyun pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3741*4882a593Smuzhiyun pSMB->t2.MaxSetupCount = 0;
3742*4882a593Smuzhiyun pSMB->t2.Reserved = 0;
3743*4882a593Smuzhiyun pSMB->t2.Flags = 0;
3744*4882a593Smuzhiyun pSMB->t2.Timeout = 0;
3745*4882a593Smuzhiyun pSMB->t2.Reserved2 = 0;
3746*4882a593Smuzhiyun pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3747*4882a593Smuzhiyun Fid) - 4);
3748*4882a593Smuzhiyun pSMB->t2.DataCount = 0;
3749*4882a593Smuzhiyun pSMB->t2.DataOffset = 0;
3750*4882a593Smuzhiyun pSMB->t2.SetupCount = 1;
3751*4882a593Smuzhiyun pSMB->t2.Reserved3 = 0;
3752*4882a593Smuzhiyun pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3753*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
3754*4882a593Smuzhiyun pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3755*4882a593Smuzhiyun pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3756*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3757*4882a593Smuzhiyun pSMB->Pad = 0;
3758*4882a593Smuzhiyun pSMB->Fid = netfid;
3759*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
3760*4882a593Smuzhiyun pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3761*4882a593Smuzhiyun
3762*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3763*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3764*4882a593Smuzhiyun if (rc) {
3765*4882a593Smuzhiyun cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
3766*4882a593Smuzhiyun } else {
3767*4882a593Smuzhiyun /* decode response */
3768*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3769*4882a593Smuzhiyun /* BB also check enough total bytes returned */
3770*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 2)
3771*4882a593Smuzhiyun /* If rc should we check for EOPNOSUPP and
3772*4882a593Smuzhiyun disable the srvino flag? or in caller? */
3773*4882a593Smuzhiyun rc = -EIO; /* bad smb */
3774*4882a593Smuzhiyun else {
3775*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3776*4882a593Smuzhiyun __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3777*4882a593Smuzhiyun struct file_chattr_info *pfinfo;
3778*4882a593Smuzhiyun /* BB Do we need a cast or hash here ? */
3779*4882a593Smuzhiyun if (count != 16) {
3780*4882a593Smuzhiyun cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
3781*4882a593Smuzhiyun rc = -EIO;
3782*4882a593Smuzhiyun goto GetExtAttrOut;
3783*4882a593Smuzhiyun }
3784*4882a593Smuzhiyun pfinfo = (struct file_chattr_info *)
3785*4882a593Smuzhiyun (data_offset + (char *) &pSMBr->hdr.Protocol);
3786*4882a593Smuzhiyun *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3787*4882a593Smuzhiyun *pMask = le64_to_cpu(pfinfo->mask);
3788*4882a593Smuzhiyun }
3789*4882a593Smuzhiyun }
3790*4882a593Smuzhiyun GetExtAttrOut:
3791*4882a593Smuzhiyun cifs_buf_release(pSMB);
3792*4882a593Smuzhiyun if (rc == -EAGAIN)
3793*4882a593Smuzhiyun goto GetExtAttrRetry;
3794*4882a593Smuzhiyun return rc;
3795*4882a593Smuzhiyun }
3796*4882a593Smuzhiyun
3797*4882a593Smuzhiyun #endif /* CONFIG_POSIX */
3798*4882a593Smuzhiyun
3799*4882a593Smuzhiyun /*
3800*4882a593Smuzhiyun * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3801*4882a593Smuzhiyun * all NT TRANSACTS that we init here have total parm and data under about 400
3802*4882a593Smuzhiyun * bytes (to fit in small cifs buffer size), which is the case so far, it
3803*4882a593Smuzhiyun * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3804*4882a593Smuzhiyun * returned setup area) and MaxParameterCount (returned parms size) must be set
3805*4882a593Smuzhiyun * by caller
3806*4882a593Smuzhiyun */
3807*4882a593Smuzhiyun static int
smb_init_nttransact(const __u16 sub_command,const int setup_count,const int parm_len,struct cifs_tcon * tcon,void ** ret_buf)3808*4882a593Smuzhiyun smb_init_nttransact(const __u16 sub_command, const int setup_count,
3809*4882a593Smuzhiyun const int parm_len, struct cifs_tcon *tcon,
3810*4882a593Smuzhiyun void **ret_buf)
3811*4882a593Smuzhiyun {
3812*4882a593Smuzhiyun int rc;
3813*4882a593Smuzhiyun __u32 temp_offset;
3814*4882a593Smuzhiyun struct smb_com_ntransact_req *pSMB;
3815*4882a593Smuzhiyun
3816*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3817*4882a593Smuzhiyun (void **)&pSMB);
3818*4882a593Smuzhiyun if (rc)
3819*4882a593Smuzhiyun return rc;
3820*4882a593Smuzhiyun *ret_buf = (void *)pSMB;
3821*4882a593Smuzhiyun pSMB->Reserved = 0;
3822*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3823*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
3824*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
3825*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
3826*4882a593Smuzhiyun pSMB->DataCount = pSMB->TotalDataCount;
3827*4882a593Smuzhiyun temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3828*4882a593Smuzhiyun (setup_count * 2) - 4 /* for rfc1001 length itself */;
3829*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3830*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3831*4882a593Smuzhiyun pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3832*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(sub_command);
3833*4882a593Smuzhiyun return 0;
3834*4882a593Smuzhiyun }
3835*4882a593Smuzhiyun
3836*4882a593Smuzhiyun static int
validate_ntransact(char * buf,char ** ppparm,char ** ppdata,__u32 * pparmlen,__u32 * pdatalen)3837*4882a593Smuzhiyun validate_ntransact(char *buf, char **ppparm, char **ppdata,
3838*4882a593Smuzhiyun __u32 *pparmlen, __u32 *pdatalen)
3839*4882a593Smuzhiyun {
3840*4882a593Smuzhiyun char *end_of_smb;
3841*4882a593Smuzhiyun __u32 data_count, data_offset, parm_count, parm_offset;
3842*4882a593Smuzhiyun struct smb_com_ntransact_rsp *pSMBr;
3843*4882a593Smuzhiyun u16 bcc;
3844*4882a593Smuzhiyun
3845*4882a593Smuzhiyun *pdatalen = 0;
3846*4882a593Smuzhiyun *pparmlen = 0;
3847*4882a593Smuzhiyun
3848*4882a593Smuzhiyun if (buf == NULL)
3849*4882a593Smuzhiyun return -EINVAL;
3850*4882a593Smuzhiyun
3851*4882a593Smuzhiyun pSMBr = (struct smb_com_ntransact_rsp *)buf;
3852*4882a593Smuzhiyun
3853*4882a593Smuzhiyun bcc = get_bcc(&pSMBr->hdr);
3854*4882a593Smuzhiyun end_of_smb = 2 /* sizeof byte count */ + bcc +
3855*4882a593Smuzhiyun (char *)&pSMBr->ByteCount;
3856*4882a593Smuzhiyun
3857*4882a593Smuzhiyun data_offset = le32_to_cpu(pSMBr->DataOffset);
3858*4882a593Smuzhiyun data_count = le32_to_cpu(pSMBr->DataCount);
3859*4882a593Smuzhiyun parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3860*4882a593Smuzhiyun parm_count = le32_to_cpu(pSMBr->ParameterCount);
3861*4882a593Smuzhiyun
3862*4882a593Smuzhiyun *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3863*4882a593Smuzhiyun *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3864*4882a593Smuzhiyun
3865*4882a593Smuzhiyun /* should we also check that parm and data areas do not overlap? */
3866*4882a593Smuzhiyun if (*ppparm > end_of_smb) {
3867*4882a593Smuzhiyun cifs_dbg(FYI, "parms start after end of smb\n");
3868*4882a593Smuzhiyun return -EINVAL;
3869*4882a593Smuzhiyun } else if (parm_count + *ppparm > end_of_smb) {
3870*4882a593Smuzhiyun cifs_dbg(FYI, "parm end after end of smb\n");
3871*4882a593Smuzhiyun return -EINVAL;
3872*4882a593Smuzhiyun } else if (*ppdata > end_of_smb) {
3873*4882a593Smuzhiyun cifs_dbg(FYI, "data starts after end of smb\n");
3874*4882a593Smuzhiyun return -EINVAL;
3875*4882a593Smuzhiyun } else if (data_count + *ppdata > end_of_smb) {
3876*4882a593Smuzhiyun cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3877*4882a593Smuzhiyun *ppdata, data_count, (data_count + *ppdata),
3878*4882a593Smuzhiyun end_of_smb, pSMBr);
3879*4882a593Smuzhiyun return -EINVAL;
3880*4882a593Smuzhiyun } else if (parm_count + data_count > bcc) {
3881*4882a593Smuzhiyun cifs_dbg(FYI, "parm count and data count larger than SMB\n");
3882*4882a593Smuzhiyun return -EINVAL;
3883*4882a593Smuzhiyun }
3884*4882a593Smuzhiyun *pdatalen = data_count;
3885*4882a593Smuzhiyun *pparmlen = parm_count;
3886*4882a593Smuzhiyun return 0;
3887*4882a593Smuzhiyun }
3888*4882a593Smuzhiyun
3889*4882a593Smuzhiyun /* Get Security Descriptor (by handle) from remote server for a file or dir */
3890*4882a593Smuzhiyun int
CIFSSMBGetCIFSACL(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid,struct cifs_ntsd ** acl_inf,__u32 * pbuflen)3891*4882a593Smuzhiyun CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3892*4882a593Smuzhiyun struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3893*4882a593Smuzhiyun {
3894*4882a593Smuzhiyun int rc = 0;
3895*4882a593Smuzhiyun int buf_type = 0;
3896*4882a593Smuzhiyun QUERY_SEC_DESC_REQ *pSMB;
3897*4882a593Smuzhiyun struct kvec iov[1];
3898*4882a593Smuzhiyun struct kvec rsp_iov;
3899*4882a593Smuzhiyun
3900*4882a593Smuzhiyun cifs_dbg(FYI, "GetCifsACL\n");
3901*4882a593Smuzhiyun
3902*4882a593Smuzhiyun *pbuflen = 0;
3903*4882a593Smuzhiyun *acl_inf = NULL;
3904*4882a593Smuzhiyun
3905*4882a593Smuzhiyun rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3906*4882a593Smuzhiyun 8 /* parm len */, tcon, (void **) &pSMB);
3907*4882a593Smuzhiyun if (rc)
3908*4882a593Smuzhiyun return rc;
3909*4882a593Smuzhiyun
3910*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le32(4);
3911*4882a593Smuzhiyun /* BB TEST with big acls that might need to be e.g. larger than 16K */
3912*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3913*4882a593Smuzhiyun pSMB->Fid = fid; /* file handle always le */
3914*4882a593Smuzhiyun pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3915*4882a593Smuzhiyun CIFS_ACL_DACL);
3916*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3917*4882a593Smuzhiyun inc_rfc1001_len(pSMB, 11);
3918*4882a593Smuzhiyun iov[0].iov_base = (char *)pSMB;
3919*4882a593Smuzhiyun iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3920*4882a593Smuzhiyun
3921*4882a593Smuzhiyun rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3922*4882a593Smuzhiyun 0, &rsp_iov);
3923*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
3924*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3925*4882a593Smuzhiyun if (rc) {
3926*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
3927*4882a593Smuzhiyun } else { /* decode response */
3928*4882a593Smuzhiyun __le32 *parm;
3929*4882a593Smuzhiyun __u32 parm_len;
3930*4882a593Smuzhiyun __u32 acl_len;
3931*4882a593Smuzhiyun struct smb_com_ntransact_rsp *pSMBr;
3932*4882a593Smuzhiyun char *pdata;
3933*4882a593Smuzhiyun
3934*4882a593Smuzhiyun /* validate_nttransact */
3935*4882a593Smuzhiyun rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
3936*4882a593Smuzhiyun &pdata, &parm_len, pbuflen);
3937*4882a593Smuzhiyun if (rc)
3938*4882a593Smuzhiyun goto qsec_out;
3939*4882a593Smuzhiyun pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
3940*4882a593Smuzhiyun
3941*4882a593Smuzhiyun cifs_dbg(FYI, "smb %p parm %p data %p\n",
3942*4882a593Smuzhiyun pSMBr, parm, *acl_inf);
3943*4882a593Smuzhiyun
3944*4882a593Smuzhiyun if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3945*4882a593Smuzhiyun rc = -EIO; /* bad smb */
3946*4882a593Smuzhiyun *pbuflen = 0;
3947*4882a593Smuzhiyun goto qsec_out;
3948*4882a593Smuzhiyun }
3949*4882a593Smuzhiyun
3950*4882a593Smuzhiyun /* BB check that data area is minimum length and as big as acl_len */
3951*4882a593Smuzhiyun
3952*4882a593Smuzhiyun acl_len = le32_to_cpu(*parm);
3953*4882a593Smuzhiyun if (acl_len != *pbuflen) {
3954*4882a593Smuzhiyun cifs_dbg(VFS, "acl length %d does not match %d\n",
3955*4882a593Smuzhiyun acl_len, *pbuflen);
3956*4882a593Smuzhiyun if (*pbuflen > acl_len)
3957*4882a593Smuzhiyun *pbuflen = acl_len;
3958*4882a593Smuzhiyun }
3959*4882a593Smuzhiyun
3960*4882a593Smuzhiyun /* check if buffer is big enough for the acl
3961*4882a593Smuzhiyun header followed by the smallest SID */
3962*4882a593Smuzhiyun if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3963*4882a593Smuzhiyun (*pbuflen >= 64 * 1024)) {
3964*4882a593Smuzhiyun cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
3965*4882a593Smuzhiyun rc = -EINVAL;
3966*4882a593Smuzhiyun *pbuflen = 0;
3967*4882a593Smuzhiyun } else {
3968*4882a593Smuzhiyun *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
3969*4882a593Smuzhiyun if (*acl_inf == NULL) {
3970*4882a593Smuzhiyun *pbuflen = 0;
3971*4882a593Smuzhiyun rc = -ENOMEM;
3972*4882a593Smuzhiyun }
3973*4882a593Smuzhiyun }
3974*4882a593Smuzhiyun }
3975*4882a593Smuzhiyun qsec_out:
3976*4882a593Smuzhiyun free_rsp_buf(buf_type, rsp_iov.iov_base);
3977*4882a593Smuzhiyun return rc;
3978*4882a593Smuzhiyun }
3979*4882a593Smuzhiyun
3980*4882a593Smuzhiyun int
CIFSSMBSetCIFSACL(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid,struct cifs_ntsd * pntsd,__u32 acllen,int aclflag)3981*4882a593Smuzhiyun CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3982*4882a593Smuzhiyun struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3983*4882a593Smuzhiyun {
3984*4882a593Smuzhiyun __u16 byte_count, param_count, data_count, param_offset, data_offset;
3985*4882a593Smuzhiyun int rc = 0;
3986*4882a593Smuzhiyun int bytes_returned = 0;
3987*4882a593Smuzhiyun SET_SEC_DESC_REQ *pSMB = NULL;
3988*4882a593Smuzhiyun void *pSMBr;
3989*4882a593Smuzhiyun
3990*4882a593Smuzhiyun setCifsAclRetry:
3991*4882a593Smuzhiyun rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
3992*4882a593Smuzhiyun if (rc)
3993*4882a593Smuzhiyun return rc;
3994*4882a593Smuzhiyun
3995*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
3996*4882a593Smuzhiyun pSMB->Reserved = 0;
3997*4882a593Smuzhiyun
3998*4882a593Smuzhiyun param_count = 8;
3999*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4000*4882a593Smuzhiyun data_count = acllen;
4001*4882a593Smuzhiyun data_offset = param_offset + param_count;
4002*4882a593Smuzhiyun byte_count = 3 /* pad */ + param_count;
4003*4882a593Smuzhiyun
4004*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le32(data_count);
4005*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
4006*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le32(4);
4007*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le32(16384);
4008*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le32(param_count);
4009*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le32(param_offset);
4010*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
4011*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le32(data_offset);
4012*4882a593Smuzhiyun pSMB->SetupCount = 0;
4013*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4014*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4015*4882a593Smuzhiyun
4016*4882a593Smuzhiyun pSMB->Fid = fid; /* file handle always le */
4017*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4018*4882a593Smuzhiyun pSMB->AclFlags = cpu_to_le32(aclflag);
4019*4882a593Smuzhiyun
4020*4882a593Smuzhiyun if (pntsd && acllen) {
4021*4882a593Smuzhiyun memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4022*4882a593Smuzhiyun data_offset, pntsd, acllen);
4023*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count + data_count);
4024*4882a593Smuzhiyun } else
4025*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4026*4882a593Smuzhiyun
4027*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4028*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4029*4882a593Smuzhiyun
4030*4882a593Smuzhiyun cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4031*4882a593Smuzhiyun bytes_returned, rc);
4032*4882a593Smuzhiyun if (rc)
4033*4882a593Smuzhiyun cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
4034*4882a593Smuzhiyun cifs_buf_release(pSMB);
4035*4882a593Smuzhiyun
4036*4882a593Smuzhiyun if (rc == -EAGAIN)
4037*4882a593Smuzhiyun goto setCifsAclRetry;
4038*4882a593Smuzhiyun
4039*4882a593Smuzhiyun return (rc);
4040*4882a593Smuzhiyun }
4041*4882a593Smuzhiyun
4042*4882a593Smuzhiyun
4043*4882a593Smuzhiyun /* Legacy Query Path Information call for lookup to old servers such
4044*4882a593Smuzhiyun as Win9x/WinME */
4045*4882a593Smuzhiyun int
SMBQueryInformation(const unsigned int xid,struct cifs_tcon * tcon,const char * search_name,FILE_ALL_INFO * data,const struct nls_table * nls_codepage,int remap)4046*4882a593Smuzhiyun SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4047*4882a593Smuzhiyun const char *search_name, FILE_ALL_INFO *data,
4048*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
4049*4882a593Smuzhiyun {
4050*4882a593Smuzhiyun QUERY_INFORMATION_REQ *pSMB;
4051*4882a593Smuzhiyun QUERY_INFORMATION_RSP *pSMBr;
4052*4882a593Smuzhiyun int rc = 0;
4053*4882a593Smuzhiyun int bytes_returned;
4054*4882a593Smuzhiyun int name_len;
4055*4882a593Smuzhiyun
4056*4882a593Smuzhiyun cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
4057*4882a593Smuzhiyun QInfRetry:
4058*4882a593Smuzhiyun rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
4059*4882a593Smuzhiyun (void **) &pSMBr);
4060*4882a593Smuzhiyun if (rc)
4061*4882a593Smuzhiyun return rc;
4062*4882a593Smuzhiyun
4063*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064*4882a593Smuzhiyun name_len =
4065*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName,
4066*4882a593Smuzhiyun search_name, PATH_MAX, nls_codepage,
4067*4882a593Smuzhiyun remap);
4068*4882a593Smuzhiyun name_len++; /* trailing null */
4069*4882a593Smuzhiyun name_len *= 2;
4070*4882a593Smuzhiyun } else {
4071*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, search_name);
4072*4882a593Smuzhiyun }
4073*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
4074*4882a593Smuzhiyun name_len++; /* account for buffer type byte */
4075*4882a593Smuzhiyun inc_rfc1001_len(pSMB, (__u16)name_len);
4076*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(name_len);
4077*4882a593Smuzhiyun
4078*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4079*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4080*4882a593Smuzhiyun if (rc) {
4081*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
4082*4882a593Smuzhiyun } else if (data) {
4083*4882a593Smuzhiyun struct timespec64 ts;
4084*4882a593Smuzhiyun __u32 time = le32_to_cpu(pSMBr->last_write_time);
4085*4882a593Smuzhiyun
4086*4882a593Smuzhiyun /* decode response */
4087*4882a593Smuzhiyun /* BB FIXME - add time zone adjustment BB */
4088*4882a593Smuzhiyun memset(data, 0, sizeof(FILE_ALL_INFO));
4089*4882a593Smuzhiyun ts.tv_nsec = 0;
4090*4882a593Smuzhiyun ts.tv_sec = time;
4091*4882a593Smuzhiyun /* decode time fields */
4092*4882a593Smuzhiyun data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4093*4882a593Smuzhiyun data->LastWriteTime = data->ChangeTime;
4094*4882a593Smuzhiyun data->LastAccessTime = 0;
4095*4882a593Smuzhiyun data->AllocationSize =
4096*4882a593Smuzhiyun cpu_to_le64(le32_to_cpu(pSMBr->size));
4097*4882a593Smuzhiyun data->EndOfFile = data->AllocationSize;
4098*4882a593Smuzhiyun data->Attributes =
4099*4882a593Smuzhiyun cpu_to_le32(le16_to_cpu(pSMBr->attr));
4100*4882a593Smuzhiyun } else
4101*4882a593Smuzhiyun rc = -EIO; /* bad buffer passed in */
4102*4882a593Smuzhiyun
4103*4882a593Smuzhiyun cifs_buf_release(pSMB);
4104*4882a593Smuzhiyun
4105*4882a593Smuzhiyun if (rc == -EAGAIN)
4106*4882a593Smuzhiyun goto QInfRetry;
4107*4882a593Smuzhiyun
4108*4882a593Smuzhiyun return rc;
4109*4882a593Smuzhiyun }
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun int
CIFSSMBQFileInfo(const unsigned int xid,struct cifs_tcon * tcon,u16 netfid,FILE_ALL_INFO * pFindData)4112*4882a593Smuzhiyun CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4113*4882a593Smuzhiyun u16 netfid, FILE_ALL_INFO *pFindData)
4114*4882a593Smuzhiyun {
4115*4882a593Smuzhiyun struct smb_t2_qfi_req *pSMB = NULL;
4116*4882a593Smuzhiyun struct smb_t2_qfi_rsp *pSMBr = NULL;
4117*4882a593Smuzhiyun int rc = 0;
4118*4882a593Smuzhiyun int bytes_returned;
4119*4882a593Smuzhiyun __u16 params, byte_count;
4120*4882a593Smuzhiyun
4121*4882a593Smuzhiyun QFileInfoRetry:
4122*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4123*4882a593Smuzhiyun (void **) &pSMBr);
4124*4882a593Smuzhiyun if (rc)
4125*4882a593Smuzhiyun return rc;
4126*4882a593Smuzhiyun
4127*4882a593Smuzhiyun params = 2 /* level */ + 2 /* fid */;
4128*4882a593Smuzhiyun pSMB->t2.TotalDataCount = 0;
4129*4882a593Smuzhiyun pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4130*4882a593Smuzhiyun /* BB find exact max data count below from sess structure BB */
4131*4882a593Smuzhiyun pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4132*4882a593Smuzhiyun pSMB->t2.MaxSetupCount = 0;
4133*4882a593Smuzhiyun pSMB->t2.Reserved = 0;
4134*4882a593Smuzhiyun pSMB->t2.Flags = 0;
4135*4882a593Smuzhiyun pSMB->t2.Timeout = 0;
4136*4882a593Smuzhiyun pSMB->t2.Reserved2 = 0;
4137*4882a593Smuzhiyun pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4138*4882a593Smuzhiyun Fid) - 4);
4139*4882a593Smuzhiyun pSMB->t2.DataCount = 0;
4140*4882a593Smuzhiyun pSMB->t2.DataOffset = 0;
4141*4882a593Smuzhiyun pSMB->t2.SetupCount = 1;
4142*4882a593Smuzhiyun pSMB->t2.Reserved3 = 0;
4143*4882a593Smuzhiyun pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4144*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4145*4882a593Smuzhiyun pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4146*4882a593Smuzhiyun pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4147*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4148*4882a593Smuzhiyun pSMB->Pad = 0;
4149*4882a593Smuzhiyun pSMB->Fid = netfid;
4150*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4151*4882a593Smuzhiyun pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4152*4882a593Smuzhiyun
4153*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4154*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4155*4882a593Smuzhiyun if (rc) {
4156*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
4157*4882a593Smuzhiyun } else { /* decode response */
4158*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4159*4882a593Smuzhiyun
4160*4882a593Smuzhiyun if (rc) /* BB add auto retry on EOPNOTSUPP? */
4161*4882a593Smuzhiyun rc = -EIO;
4162*4882a593Smuzhiyun else if (get_bcc(&pSMBr->hdr) < 40)
4163*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4164*4882a593Smuzhiyun else if (pFindData) {
4165*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4166*4882a593Smuzhiyun memcpy((char *) pFindData,
4167*4882a593Smuzhiyun (char *) &pSMBr->hdr.Protocol +
4168*4882a593Smuzhiyun data_offset, sizeof(FILE_ALL_INFO));
4169*4882a593Smuzhiyun } else
4170*4882a593Smuzhiyun rc = -ENOMEM;
4171*4882a593Smuzhiyun }
4172*4882a593Smuzhiyun cifs_buf_release(pSMB);
4173*4882a593Smuzhiyun if (rc == -EAGAIN)
4174*4882a593Smuzhiyun goto QFileInfoRetry;
4175*4882a593Smuzhiyun
4176*4882a593Smuzhiyun return rc;
4177*4882a593Smuzhiyun }
4178*4882a593Smuzhiyun
4179*4882a593Smuzhiyun int
CIFSSMBQPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * search_name,FILE_ALL_INFO * data,int legacy,const struct nls_table * nls_codepage,int remap)4180*4882a593Smuzhiyun CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4181*4882a593Smuzhiyun const char *search_name, FILE_ALL_INFO *data,
4182*4882a593Smuzhiyun int legacy /* old style infolevel */,
4183*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
4184*4882a593Smuzhiyun {
4185*4882a593Smuzhiyun /* level 263 SMB_QUERY_FILE_ALL_INFO */
4186*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
4187*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
4188*4882a593Smuzhiyun int rc = 0;
4189*4882a593Smuzhiyun int bytes_returned;
4190*4882a593Smuzhiyun int name_len;
4191*4882a593Smuzhiyun __u16 params, byte_count;
4192*4882a593Smuzhiyun
4193*4882a593Smuzhiyun /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
4194*4882a593Smuzhiyun QPathInfoRetry:
4195*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4196*4882a593Smuzhiyun (void **) &pSMBr);
4197*4882a593Smuzhiyun if (rc)
4198*4882a593Smuzhiyun return rc;
4199*4882a593Smuzhiyun
4200*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4201*4882a593Smuzhiyun name_len =
4202*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
4203*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
4204*4882a593Smuzhiyun name_len++; /* trailing null */
4205*4882a593Smuzhiyun name_len *= 2;
4206*4882a593Smuzhiyun } else {
4207*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, search_name);
4208*4882a593Smuzhiyun }
4209*4882a593Smuzhiyun
4210*4882a593Smuzhiyun params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4211*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
4212*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
4213*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
4214*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4000);
4215*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4216*4882a593Smuzhiyun pSMB->Reserved = 0;
4217*4882a593Smuzhiyun pSMB->Flags = 0;
4218*4882a593Smuzhiyun pSMB->Timeout = 0;
4219*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4220*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
4221*4882a593Smuzhiyun struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4222*4882a593Smuzhiyun pSMB->DataCount = 0;
4223*4882a593Smuzhiyun pSMB->DataOffset = 0;
4224*4882a593Smuzhiyun pSMB->SetupCount = 1;
4225*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4226*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4227*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4228*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4229*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4230*4882a593Smuzhiyun if (legacy)
4231*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4232*4882a593Smuzhiyun else
4233*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4234*4882a593Smuzhiyun pSMB->Reserved4 = 0;
4235*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4236*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4237*4882a593Smuzhiyun
4238*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4239*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4240*4882a593Smuzhiyun if (rc) {
4241*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
4242*4882a593Smuzhiyun } else { /* decode response */
4243*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4244*4882a593Smuzhiyun
4245*4882a593Smuzhiyun if (rc) /* BB add auto retry on EOPNOTSUPP? */
4246*4882a593Smuzhiyun rc = -EIO;
4247*4882a593Smuzhiyun else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
4248*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4249*4882a593Smuzhiyun else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4250*4882a593Smuzhiyun rc = -EIO; /* 24 or 26 expected but we do not read
4251*4882a593Smuzhiyun last field */
4252*4882a593Smuzhiyun else if (data) {
4253*4882a593Smuzhiyun int size;
4254*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4255*4882a593Smuzhiyun
4256*4882a593Smuzhiyun /*
4257*4882a593Smuzhiyun * On legacy responses we do not read the last field,
4258*4882a593Smuzhiyun * EAsize, fortunately since it varies by subdialect and
4259*4882a593Smuzhiyun * also note it differs on Set vs Get, ie two bytes or 4
4260*4882a593Smuzhiyun * bytes depending but we don't care here.
4261*4882a593Smuzhiyun */
4262*4882a593Smuzhiyun if (legacy)
4263*4882a593Smuzhiyun size = sizeof(FILE_INFO_STANDARD);
4264*4882a593Smuzhiyun else
4265*4882a593Smuzhiyun size = sizeof(FILE_ALL_INFO);
4266*4882a593Smuzhiyun memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
4267*4882a593Smuzhiyun data_offset, size);
4268*4882a593Smuzhiyun } else
4269*4882a593Smuzhiyun rc = -ENOMEM;
4270*4882a593Smuzhiyun }
4271*4882a593Smuzhiyun cifs_buf_release(pSMB);
4272*4882a593Smuzhiyun if (rc == -EAGAIN)
4273*4882a593Smuzhiyun goto QPathInfoRetry;
4274*4882a593Smuzhiyun
4275*4882a593Smuzhiyun return rc;
4276*4882a593Smuzhiyun }
4277*4882a593Smuzhiyun
4278*4882a593Smuzhiyun int
CIFSSMBUnixQFileInfo(const unsigned int xid,struct cifs_tcon * tcon,u16 netfid,FILE_UNIX_BASIC_INFO * pFindData)4279*4882a593Smuzhiyun CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4280*4882a593Smuzhiyun u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4281*4882a593Smuzhiyun {
4282*4882a593Smuzhiyun struct smb_t2_qfi_req *pSMB = NULL;
4283*4882a593Smuzhiyun struct smb_t2_qfi_rsp *pSMBr = NULL;
4284*4882a593Smuzhiyun int rc = 0;
4285*4882a593Smuzhiyun int bytes_returned;
4286*4882a593Smuzhiyun __u16 params, byte_count;
4287*4882a593Smuzhiyun
4288*4882a593Smuzhiyun UnixQFileInfoRetry:
4289*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4290*4882a593Smuzhiyun (void **) &pSMBr);
4291*4882a593Smuzhiyun if (rc)
4292*4882a593Smuzhiyun return rc;
4293*4882a593Smuzhiyun
4294*4882a593Smuzhiyun params = 2 /* level */ + 2 /* fid */;
4295*4882a593Smuzhiyun pSMB->t2.TotalDataCount = 0;
4296*4882a593Smuzhiyun pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4297*4882a593Smuzhiyun /* BB find exact max data count below from sess structure BB */
4298*4882a593Smuzhiyun pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4299*4882a593Smuzhiyun pSMB->t2.MaxSetupCount = 0;
4300*4882a593Smuzhiyun pSMB->t2.Reserved = 0;
4301*4882a593Smuzhiyun pSMB->t2.Flags = 0;
4302*4882a593Smuzhiyun pSMB->t2.Timeout = 0;
4303*4882a593Smuzhiyun pSMB->t2.Reserved2 = 0;
4304*4882a593Smuzhiyun pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4305*4882a593Smuzhiyun Fid) - 4);
4306*4882a593Smuzhiyun pSMB->t2.DataCount = 0;
4307*4882a593Smuzhiyun pSMB->t2.DataOffset = 0;
4308*4882a593Smuzhiyun pSMB->t2.SetupCount = 1;
4309*4882a593Smuzhiyun pSMB->t2.Reserved3 = 0;
4310*4882a593Smuzhiyun pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4311*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4312*4882a593Smuzhiyun pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4313*4882a593Smuzhiyun pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4314*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4315*4882a593Smuzhiyun pSMB->Pad = 0;
4316*4882a593Smuzhiyun pSMB->Fid = netfid;
4317*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4318*4882a593Smuzhiyun pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4319*4882a593Smuzhiyun
4320*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4321*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4322*4882a593Smuzhiyun if (rc) {
4323*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
4324*4882a593Smuzhiyun } else { /* decode response */
4325*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4326*4882a593Smuzhiyun
4327*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4328*4882a593Smuzhiyun cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4329*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4330*4882a593Smuzhiyun } else {
4331*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4332*4882a593Smuzhiyun memcpy((char *) pFindData,
4333*4882a593Smuzhiyun (char *) &pSMBr->hdr.Protocol +
4334*4882a593Smuzhiyun data_offset,
4335*4882a593Smuzhiyun sizeof(FILE_UNIX_BASIC_INFO));
4336*4882a593Smuzhiyun }
4337*4882a593Smuzhiyun }
4338*4882a593Smuzhiyun
4339*4882a593Smuzhiyun cifs_buf_release(pSMB);
4340*4882a593Smuzhiyun if (rc == -EAGAIN)
4341*4882a593Smuzhiyun goto UnixQFileInfoRetry;
4342*4882a593Smuzhiyun
4343*4882a593Smuzhiyun return rc;
4344*4882a593Smuzhiyun }
4345*4882a593Smuzhiyun
4346*4882a593Smuzhiyun int
CIFSSMBUnixQPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,FILE_UNIX_BASIC_INFO * pFindData,const struct nls_table * nls_codepage,int remap)4347*4882a593Smuzhiyun CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4348*4882a593Smuzhiyun const unsigned char *searchName,
4349*4882a593Smuzhiyun FILE_UNIX_BASIC_INFO *pFindData,
4350*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
4351*4882a593Smuzhiyun {
4352*4882a593Smuzhiyun /* SMB_QUERY_FILE_UNIX_BASIC */
4353*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
4354*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
4355*4882a593Smuzhiyun int rc = 0;
4356*4882a593Smuzhiyun int bytes_returned = 0;
4357*4882a593Smuzhiyun int name_len;
4358*4882a593Smuzhiyun __u16 params, byte_count;
4359*4882a593Smuzhiyun
4360*4882a593Smuzhiyun cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
4361*4882a593Smuzhiyun UnixQPathInfoRetry:
4362*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4363*4882a593Smuzhiyun (void **) &pSMBr);
4364*4882a593Smuzhiyun if (rc)
4365*4882a593Smuzhiyun return rc;
4366*4882a593Smuzhiyun
4367*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4368*4882a593Smuzhiyun name_len =
4369*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4370*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
4371*4882a593Smuzhiyun name_len++; /* trailing null */
4372*4882a593Smuzhiyun name_len *= 2;
4373*4882a593Smuzhiyun } else {
4374*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, searchName);
4375*4882a593Smuzhiyun }
4376*4882a593Smuzhiyun
4377*4882a593Smuzhiyun params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
4378*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
4379*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
4380*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
4381*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4000);
4382*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4383*4882a593Smuzhiyun pSMB->Reserved = 0;
4384*4882a593Smuzhiyun pSMB->Flags = 0;
4385*4882a593Smuzhiyun pSMB->Timeout = 0;
4386*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4387*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
4388*4882a593Smuzhiyun struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4389*4882a593Smuzhiyun pSMB->DataCount = 0;
4390*4882a593Smuzhiyun pSMB->DataOffset = 0;
4391*4882a593Smuzhiyun pSMB->SetupCount = 1;
4392*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4393*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4394*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4395*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4396*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4397*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4398*4882a593Smuzhiyun pSMB->Reserved4 = 0;
4399*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4400*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4401*4882a593Smuzhiyun
4402*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4403*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4404*4882a593Smuzhiyun if (rc) {
4405*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
4406*4882a593Smuzhiyun } else { /* decode response */
4407*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4408*4882a593Smuzhiyun
4409*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4410*4882a593Smuzhiyun cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4411*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4412*4882a593Smuzhiyun } else {
4413*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4414*4882a593Smuzhiyun memcpy((char *) pFindData,
4415*4882a593Smuzhiyun (char *) &pSMBr->hdr.Protocol +
4416*4882a593Smuzhiyun data_offset,
4417*4882a593Smuzhiyun sizeof(FILE_UNIX_BASIC_INFO));
4418*4882a593Smuzhiyun }
4419*4882a593Smuzhiyun }
4420*4882a593Smuzhiyun cifs_buf_release(pSMB);
4421*4882a593Smuzhiyun if (rc == -EAGAIN)
4422*4882a593Smuzhiyun goto UnixQPathInfoRetry;
4423*4882a593Smuzhiyun
4424*4882a593Smuzhiyun return rc;
4425*4882a593Smuzhiyun }
4426*4882a593Smuzhiyun
4427*4882a593Smuzhiyun /* xid, tcon, searchName and codepage are input parms, rest are returned */
4428*4882a593Smuzhiyun int
CIFSFindFirst(const unsigned int xid,struct cifs_tcon * tcon,const char * searchName,struct cifs_sb_info * cifs_sb,__u16 * pnetfid,__u16 search_flags,struct cifs_search_info * psrch_inf,bool msearch)4429*4882a593Smuzhiyun CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4430*4882a593Smuzhiyun const char *searchName, struct cifs_sb_info *cifs_sb,
4431*4882a593Smuzhiyun __u16 *pnetfid, __u16 search_flags,
4432*4882a593Smuzhiyun struct cifs_search_info *psrch_inf, bool msearch)
4433*4882a593Smuzhiyun {
4434*4882a593Smuzhiyun /* level 257 SMB_ */
4435*4882a593Smuzhiyun TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4436*4882a593Smuzhiyun TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
4437*4882a593Smuzhiyun T2_FFIRST_RSP_PARMS *parms;
4438*4882a593Smuzhiyun int rc = 0;
4439*4882a593Smuzhiyun int bytes_returned = 0;
4440*4882a593Smuzhiyun int name_len, remap;
4441*4882a593Smuzhiyun __u16 params, byte_count;
4442*4882a593Smuzhiyun struct nls_table *nls_codepage;
4443*4882a593Smuzhiyun
4444*4882a593Smuzhiyun cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
4445*4882a593Smuzhiyun
4446*4882a593Smuzhiyun findFirstRetry:
4447*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4448*4882a593Smuzhiyun (void **) &pSMBr);
4449*4882a593Smuzhiyun if (rc)
4450*4882a593Smuzhiyun return rc;
4451*4882a593Smuzhiyun
4452*4882a593Smuzhiyun nls_codepage = cifs_sb->local_nls;
4453*4882a593Smuzhiyun remap = cifs_remap(cifs_sb);
4454*4882a593Smuzhiyun
4455*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4456*4882a593Smuzhiyun name_len =
4457*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4458*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
4459*4882a593Smuzhiyun /* We can not add the asterik earlier in case
4460*4882a593Smuzhiyun it got remapped to 0xF03A as if it were part of the
4461*4882a593Smuzhiyun directory name instead of a wildcard */
4462*4882a593Smuzhiyun name_len *= 2;
4463*4882a593Smuzhiyun if (msearch) {
4464*4882a593Smuzhiyun pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4465*4882a593Smuzhiyun pSMB->FileName[name_len+1] = 0;
4466*4882a593Smuzhiyun pSMB->FileName[name_len+2] = '*';
4467*4882a593Smuzhiyun pSMB->FileName[name_len+3] = 0;
4468*4882a593Smuzhiyun name_len += 4; /* now the trailing null */
4469*4882a593Smuzhiyun /* null terminate just in case */
4470*4882a593Smuzhiyun pSMB->FileName[name_len] = 0;
4471*4882a593Smuzhiyun pSMB->FileName[name_len+1] = 0;
4472*4882a593Smuzhiyun name_len += 2;
4473*4882a593Smuzhiyun }
4474*4882a593Smuzhiyun } else {
4475*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, searchName);
4476*4882a593Smuzhiyun if (msearch) {
4477*4882a593Smuzhiyun if (WARN_ON_ONCE(name_len > PATH_MAX-2))
4478*4882a593Smuzhiyun name_len = PATH_MAX-2;
4479*4882a593Smuzhiyun /* overwrite nul byte */
4480*4882a593Smuzhiyun pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
4481*4882a593Smuzhiyun pSMB->FileName[name_len] = '*';
4482*4882a593Smuzhiyun pSMB->FileName[name_len+1] = 0;
4483*4882a593Smuzhiyun name_len += 2;
4484*4882a593Smuzhiyun }
4485*4882a593Smuzhiyun }
4486*4882a593Smuzhiyun
4487*4882a593Smuzhiyun params = 12 + name_len /* includes null */ ;
4488*4882a593Smuzhiyun pSMB->TotalDataCount = 0; /* no EAs */
4489*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(10);
4490*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4491*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4492*4882a593Smuzhiyun pSMB->Reserved = 0;
4493*4882a593Smuzhiyun pSMB->Flags = 0;
4494*4882a593Smuzhiyun pSMB->Timeout = 0;
4495*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4496*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4497*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4498*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4499*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(
4500*4882a593Smuzhiyun offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4501*4882a593Smuzhiyun - 4);
4502*4882a593Smuzhiyun pSMB->DataCount = 0;
4503*4882a593Smuzhiyun pSMB->DataOffset = 0;
4504*4882a593Smuzhiyun pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4505*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4506*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4507*4882a593Smuzhiyun pSMB->SearchAttributes =
4508*4882a593Smuzhiyun cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4509*4882a593Smuzhiyun ATTR_DIRECTORY);
4510*4882a593Smuzhiyun pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4511*4882a593Smuzhiyun pSMB->SearchFlags = cpu_to_le16(search_flags);
4512*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4513*4882a593Smuzhiyun
4514*4882a593Smuzhiyun /* BB what should we set StorageType to? Does it matter? BB */
4515*4882a593Smuzhiyun pSMB->SearchStorageType = 0;
4516*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4517*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4518*4882a593Smuzhiyun
4519*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4520*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4521*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
4522*4882a593Smuzhiyun
4523*4882a593Smuzhiyun if (rc) {/* BB add logic to retry regular search if Unix search
4524*4882a593Smuzhiyun rejected unexpectedly by server */
4525*4882a593Smuzhiyun /* BB Add code to handle unsupported level rc */
4526*4882a593Smuzhiyun cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
4527*4882a593Smuzhiyun
4528*4882a593Smuzhiyun cifs_buf_release(pSMB);
4529*4882a593Smuzhiyun
4530*4882a593Smuzhiyun /* BB eventually could optimize out free and realloc of buf */
4531*4882a593Smuzhiyun /* for this case */
4532*4882a593Smuzhiyun if (rc == -EAGAIN)
4533*4882a593Smuzhiyun goto findFirstRetry;
4534*4882a593Smuzhiyun } else { /* decode response */
4535*4882a593Smuzhiyun /* BB remember to free buffer if error BB */
4536*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537*4882a593Smuzhiyun if (rc == 0) {
4538*4882a593Smuzhiyun unsigned int lnoff;
4539*4882a593Smuzhiyun
4540*4882a593Smuzhiyun if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4541*4882a593Smuzhiyun psrch_inf->unicode = true;
4542*4882a593Smuzhiyun else
4543*4882a593Smuzhiyun psrch_inf->unicode = false;
4544*4882a593Smuzhiyun
4545*4882a593Smuzhiyun psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4546*4882a593Smuzhiyun psrch_inf->smallBuf = false;
4547*4882a593Smuzhiyun psrch_inf->srch_entries_start =
4548*4882a593Smuzhiyun (char *) &pSMBr->hdr.Protocol +
4549*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.DataOffset);
4550*4882a593Smuzhiyun parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4551*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.ParameterOffset));
4552*4882a593Smuzhiyun
4553*4882a593Smuzhiyun if (parms->EndofSearch)
4554*4882a593Smuzhiyun psrch_inf->endOfSearch = true;
4555*4882a593Smuzhiyun else
4556*4882a593Smuzhiyun psrch_inf->endOfSearch = false;
4557*4882a593Smuzhiyun
4558*4882a593Smuzhiyun psrch_inf->entries_in_buffer =
4559*4882a593Smuzhiyun le16_to_cpu(parms->SearchCount);
4560*4882a593Smuzhiyun psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
4561*4882a593Smuzhiyun psrch_inf->entries_in_buffer;
4562*4882a593Smuzhiyun lnoff = le16_to_cpu(parms->LastNameOffset);
4563*4882a593Smuzhiyun if (CIFSMaxBufSize < lnoff) {
4564*4882a593Smuzhiyun cifs_dbg(VFS, "ignoring corrupt resume name\n");
4565*4882a593Smuzhiyun psrch_inf->last_entry = NULL;
4566*4882a593Smuzhiyun return rc;
4567*4882a593Smuzhiyun }
4568*4882a593Smuzhiyun
4569*4882a593Smuzhiyun psrch_inf->last_entry = psrch_inf->srch_entries_start +
4570*4882a593Smuzhiyun lnoff;
4571*4882a593Smuzhiyun
4572*4882a593Smuzhiyun if (pnetfid)
4573*4882a593Smuzhiyun *pnetfid = parms->SearchHandle;
4574*4882a593Smuzhiyun } else {
4575*4882a593Smuzhiyun cifs_buf_release(pSMB);
4576*4882a593Smuzhiyun }
4577*4882a593Smuzhiyun }
4578*4882a593Smuzhiyun
4579*4882a593Smuzhiyun return rc;
4580*4882a593Smuzhiyun }
4581*4882a593Smuzhiyun
CIFSFindNext(const unsigned int xid,struct cifs_tcon * tcon,__u16 searchHandle,__u16 search_flags,struct cifs_search_info * psrch_inf)4582*4882a593Smuzhiyun int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4583*4882a593Smuzhiyun __u16 searchHandle, __u16 search_flags,
4584*4882a593Smuzhiyun struct cifs_search_info *psrch_inf)
4585*4882a593Smuzhiyun {
4586*4882a593Smuzhiyun TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4587*4882a593Smuzhiyun TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
4588*4882a593Smuzhiyun T2_FNEXT_RSP_PARMS *parms;
4589*4882a593Smuzhiyun char *response_data;
4590*4882a593Smuzhiyun int rc = 0;
4591*4882a593Smuzhiyun int bytes_returned;
4592*4882a593Smuzhiyun unsigned int name_len;
4593*4882a593Smuzhiyun __u16 params, byte_count;
4594*4882a593Smuzhiyun
4595*4882a593Smuzhiyun cifs_dbg(FYI, "In FindNext\n");
4596*4882a593Smuzhiyun
4597*4882a593Smuzhiyun if (psrch_inf->endOfSearch)
4598*4882a593Smuzhiyun return -ENOENT;
4599*4882a593Smuzhiyun
4600*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601*4882a593Smuzhiyun (void **) &pSMBr);
4602*4882a593Smuzhiyun if (rc)
4603*4882a593Smuzhiyun return rc;
4604*4882a593Smuzhiyun
4605*4882a593Smuzhiyun params = 14; /* includes 2 bytes of null string, converted to LE below*/
4606*4882a593Smuzhiyun byte_count = 0;
4607*4882a593Smuzhiyun pSMB->TotalDataCount = 0; /* no EAs */
4608*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(8);
4609*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
4610*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4611*4882a593Smuzhiyun pSMB->Reserved = 0;
4612*4882a593Smuzhiyun pSMB->Flags = 0;
4613*4882a593Smuzhiyun pSMB->Timeout = 0;
4614*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4615*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(
4616*4882a593Smuzhiyun offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4617*4882a593Smuzhiyun pSMB->DataCount = 0;
4618*4882a593Smuzhiyun pSMB->DataOffset = 0;
4619*4882a593Smuzhiyun pSMB->SetupCount = 1;
4620*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4621*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4622*4882a593Smuzhiyun pSMB->SearchHandle = searchHandle; /* always kept as le */
4623*4882a593Smuzhiyun pSMB->SearchCount =
4624*4882a593Smuzhiyun cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
4625*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4626*4882a593Smuzhiyun pSMB->ResumeKey = psrch_inf->resume_key;
4627*4882a593Smuzhiyun pSMB->SearchFlags = cpu_to_le16(search_flags);
4628*4882a593Smuzhiyun
4629*4882a593Smuzhiyun name_len = psrch_inf->resume_name_len;
4630*4882a593Smuzhiyun params += name_len;
4631*4882a593Smuzhiyun if (name_len < PATH_MAX) {
4632*4882a593Smuzhiyun memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4633*4882a593Smuzhiyun byte_count += name_len;
4634*4882a593Smuzhiyun /* 14 byte parm len above enough for 2 byte null terminator */
4635*4882a593Smuzhiyun pSMB->ResumeFileName[name_len] = 0;
4636*4882a593Smuzhiyun pSMB->ResumeFileName[name_len+1] = 0;
4637*4882a593Smuzhiyun } else {
4638*4882a593Smuzhiyun rc = -EINVAL;
4639*4882a593Smuzhiyun goto FNext2_err_exit;
4640*4882a593Smuzhiyun }
4641*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4642*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4643*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4644*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4645*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4646*4882a593Smuzhiyun
4647*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4648*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4649*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
4650*4882a593Smuzhiyun if (rc) {
4651*4882a593Smuzhiyun if (rc == -EBADF) {
4652*4882a593Smuzhiyun psrch_inf->endOfSearch = true;
4653*4882a593Smuzhiyun cifs_buf_release(pSMB);
4654*4882a593Smuzhiyun rc = 0; /* search probably was closed at end of search*/
4655*4882a593Smuzhiyun } else
4656*4882a593Smuzhiyun cifs_dbg(FYI, "FindNext returned = %d\n", rc);
4657*4882a593Smuzhiyun } else { /* decode response */
4658*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4659*4882a593Smuzhiyun
4660*4882a593Smuzhiyun if (rc == 0) {
4661*4882a593Smuzhiyun unsigned int lnoff;
4662*4882a593Smuzhiyun
4663*4882a593Smuzhiyun /* BB fixme add lock for file (srch_info) struct here */
4664*4882a593Smuzhiyun if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4665*4882a593Smuzhiyun psrch_inf->unicode = true;
4666*4882a593Smuzhiyun else
4667*4882a593Smuzhiyun psrch_inf->unicode = false;
4668*4882a593Smuzhiyun response_data = (char *) &pSMBr->hdr.Protocol +
4669*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.ParameterOffset);
4670*4882a593Smuzhiyun parms = (T2_FNEXT_RSP_PARMS *)response_data;
4671*4882a593Smuzhiyun response_data = (char *)&pSMBr->hdr.Protocol +
4672*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.DataOffset);
4673*4882a593Smuzhiyun if (psrch_inf->smallBuf)
4674*4882a593Smuzhiyun cifs_small_buf_release(
4675*4882a593Smuzhiyun psrch_inf->ntwrk_buf_start);
4676*4882a593Smuzhiyun else
4677*4882a593Smuzhiyun cifs_buf_release(psrch_inf->ntwrk_buf_start);
4678*4882a593Smuzhiyun psrch_inf->srch_entries_start = response_data;
4679*4882a593Smuzhiyun psrch_inf->ntwrk_buf_start = (char *)pSMB;
4680*4882a593Smuzhiyun psrch_inf->smallBuf = false;
4681*4882a593Smuzhiyun if (parms->EndofSearch)
4682*4882a593Smuzhiyun psrch_inf->endOfSearch = true;
4683*4882a593Smuzhiyun else
4684*4882a593Smuzhiyun psrch_inf->endOfSearch = false;
4685*4882a593Smuzhiyun psrch_inf->entries_in_buffer =
4686*4882a593Smuzhiyun le16_to_cpu(parms->SearchCount);
4687*4882a593Smuzhiyun psrch_inf->index_of_last_entry +=
4688*4882a593Smuzhiyun psrch_inf->entries_in_buffer;
4689*4882a593Smuzhiyun lnoff = le16_to_cpu(parms->LastNameOffset);
4690*4882a593Smuzhiyun if (CIFSMaxBufSize < lnoff) {
4691*4882a593Smuzhiyun cifs_dbg(VFS, "ignoring corrupt resume name\n");
4692*4882a593Smuzhiyun psrch_inf->last_entry = NULL;
4693*4882a593Smuzhiyun return rc;
4694*4882a593Smuzhiyun } else
4695*4882a593Smuzhiyun psrch_inf->last_entry =
4696*4882a593Smuzhiyun psrch_inf->srch_entries_start + lnoff;
4697*4882a593Smuzhiyun
4698*4882a593Smuzhiyun /* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4699*4882a593Smuzhiyun psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
4700*4882a593Smuzhiyun
4701*4882a593Smuzhiyun /* BB fixme add unlock here */
4702*4882a593Smuzhiyun }
4703*4882a593Smuzhiyun
4704*4882a593Smuzhiyun }
4705*4882a593Smuzhiyun
4706*4882a593Smuzhiyun /* BB On error, should we leave previous search buf (and count and
4707*4882a593Smuzhiyun last entry fields) intact or free the previous one? */
4708*4882a593Smuzhiyun
4709*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
4710*4882a593Smuzhiyun since file handle passed in no longer valid */
4711*4882a593Smuzhiyun FNext2_err_exit:
4712*4882a593Smuzhiyun if (rc != 0)
4713*4882a593Smuzhiyun cifs_buf_release(pSMB);
4714*4882a593Smuzhiyun return rc;
4715*4882a593Smuzhiyun }
4716*4882a593Smuzhiyun
4717*4882a593Smuzhiyun int
CIFSFindClose(const unsigned int xid,struct cifs_tcon * tcon,const __u16 searchHandle)4718*4882a593Smuzhiyun CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
4719*4882a593Smuzhiyun const __u16 searchHandle)
4720*4882a593Smuzhiyun {
4721*4882a593Smuzhiyun int rc = 0;
4722*4882a593Smuzhiyun FINDCLOSE_REQ *pSMB = NULL;
4723*4882a593Smuzhiyun
4724*4882a593Smuzhiyun cifs_dbg(FYI, "In CIFSSMBFindClose\n");
4725*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4726*4882a593Smuzhiyun
4727*4882a593Smuzhiyun /* no sense returning error if session restarted
4728*4882a593Smuzhiyun as file handle has been closed */
4729*4882a593Smuzhiyun if (rc == -EAGAIN)
4730*4882a593Smuzhiyun return 0;
4731*4882a593Smuzhiyun if (rc)
4732*4882a593Smuzhiyun return rc;
4733*4882a593Smuzhiyun
4734*4882a593Smuzhiyun pSMB->FileID = searchHandle;
4735*4882a593Smuzhiyun pSMB->ByteCount = 0;
4736*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
4737*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
4738*4882a593Smuzhiyun if (rc)
4739*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
4740*4882a593Smuzhiyun
4741*4882a593Smuzhiyun cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
4742*4882a593Smuzhiyun
4743*4882a593Smuzhiyun /* Since session is dead, search handle closed on server already */
4744*4882a593Smuzhiyun if (rc == -EAGAIN)
4745*4882a593Smuzhiyun rc = 0;
4746*4882a593Smuzhiyun
4747*4882a593Smuzhiyun return rc;
4748*4882a593Smuzhiyun }
4749*4882a593Smuzhiyun
4750*4882a593Smuzhiyun int
CIFSGetSrvInodeNumber(const unsigned int xid,struct cifs_tcon * tcon,const char * search_name,__u64 * inode_number,const struct nls_table * nls_codepage,int remap)4751*4882a593Smuzhiyun CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
4752*4882a593Smuzhiyun const char *search_name, __u64 *inode_number,
4753*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
4754*4882a593Smuzhiyun {
4755*4882a593Smuzhiyun int rc = 0;
4756*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
4757*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
4758*4882a593Smuzhiyun int name_len, bytes_returned;
4759*4882a593Smuzhiyun __u16 params, byte_count;
4760*4882a593Smuzhiyun
4761*4882a593Smuzhiyun cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
4762*4882a593Smuzhiyun if (tcon == NULL)
4763*4882a593Smuzhiyun return -ENODEV;
4764*4882a593Smuzhiyun
4765*4882a593Smuzhiyun GetInodeNumberRetry:
4766*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4767*4882a593Smuzhiyun (void **) &pSMBr);
4768*4882a593Smuzhiyun if (rc)
4769*4882a593Smuzhiyun return rc;
4770*4882a593Smuzhiyun
4771*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4772*4882a593Smuzhiyun name_len =
4773*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName,
4774*4882a593Smuzhiyun search_name, PATH_MAX, nls_codepage,
4775*4882a593Smuzhiyun remap);
4776*4882a593Smuzhiyun name_len++; /* trailing null */
4777*4882a593Smuzhiyun name_len *= 2;
4778*4882a593Smuzhiyun } else {
4779*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, search_name);
4780*4882a593Smuzhiyun }
4781*4882a593Smuzhiyun
4782*4882a593Smuzhiyun params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4783*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
4784*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
4785*4882a593Smuzhiyun /* BB find exact max data count below from sess structure BB */
4786*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4000);
4787*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4788*4882a593Smuzhiyun pSMB->Reserved = 0;
4789*4882a593Smuzhiyun pSMB->Flags = 0;
4790*4882a593Smuzhiyun pSMB->Timeout = 0;
4791*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4792*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
4793*4882a593Smuzhiyun struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
4794*4882a593Smuzhiyun pSMB->DataCount = 0;
4795*4882a593Smuzhiyun pSMB->DataOffset = 0;
4796*4882a593Smuzhiyun pSMB->SetupCount = 1;
4797*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4798*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4799*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4800*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4801*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4802*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4803*4882a593Smuzhiyun pSMB->Reserved4 = 0;
4804*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4805*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4806*4882a593Smuzhiyun
4807*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4808*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4809*4882a593Smuzhiyun if (rc) {
4810*4882a593Smuzhiyun cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
4811*4882a593Smuzhiyun } else {
4812*4882a593Smuzhiyun /* decode response */
4813*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4814*4882a593Smuzhiyun /* BB also check enough total bytes returned */
4815*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 2)
4816*4882a593Smuzhiyun /* If rc should we check for EOPNOSUPP and
4817*4882a593Smuzhiyun disable the srvino flag? or in caller? */
4818*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4819*4882a593Smuzhiyun else {
4820*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4821*4882a593Smuzhiyun __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4822*4882a593Smuzhiyun struct file_internal_info *pfinfo;
4823*4882a593Smuzhiyun /* BB Do we need a cast or hash here ? */
4824*4882a593Smuzhiyun if (count < 8) {
4825*4882a593Smuzhiyun cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
4826*4882a593Smuzhiyun rc = -EIO;
4827*4882a593Smuzhiyun goto GetInodeNumOut;
4828*4882a593Smuzhiyun }
4829*4882a593Smuzhiyun pfinfo = (struct file_internal_info *)
4830*4882a593Smuzhiyun (data_offset + (char *) &pSMBr->hdr.Protocol);
4831*4882a593Smuzhiyun *inode_number = le64_to_cpu(pfinfo->UniqueId);
4832*4882a593Smuzhiyun }
4833*4882a593Smuzhiyun }
4834*4882a593Smuzhiyun GetInodeNumOut:
4835*4882a593Smuzhiyun cifs_buf_release(pSMB);
4836*4882a593Smuzhiyun if (rc == -EAGAIN)
4837*4882a593Smuzhiyun goto GetInodeNumberRetry;
4838*4882a593Smuzhiyun return rc;
4839*4882a593Smuzhiyun }
4840*4882a593Smuzhiyun
4841*4882a593Smuzhiyun int
CIFSGetDFSRefer(const unsigned int xid,struct cifs_ses * ses,const char * search_name,struct dfs_info3_param ** target_nodes,unsigned int * num_of_nodes,const struct nls_table * nls_codepage,int remap)4842*4882a593Smuzhiyun CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
4843*4882a593Smuzhiyun const char *search_name, struct dfs_info3_param **target_nodes,
4844*4882a593Smuzhiyun unsigned int *num_of_nodes,
4845*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
4846*4882a593Smuzhiyun {
4847*4882a593Smuzhiyun /* TRANS2_GET_DFS_REFERRAL */
4848*4882a593Smuzhiyun TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4849*4882a593Smuzhiyun TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
4850*4882a593Smuzhiyun int rc = 0;
4851*4882a593Smuzhiyun int bytes_returned;
4852*4882a593Smuzhiyun int name_len;
4853*4882a593Smuzhiyun __u16 params, byte_count;
4854*4882a593Smuzhiyun *num_of_nodes = 0;
4855*4882a593Smuzhiyun *target_nodes = NULL;
4856*4882a593Smuzhiyun
4857*4882a593Smuzhiyun cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
4858*4882a593Smuzhiyun if (ses == NULL || ses->tcon_ipc == NULL)
4859*4882a593Smuzhiyun return -ENODEV;
4860*4882a593Smuzhiyun
4861*4882a593Smuzhiyun getDFSRetry:
4862*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
4863*4882a593Smuzhiyun (void **) &pSMBr);
4864*4882a593Smuzhiyun if (rc)
4865*4882a593Smuzhiyun return rc;
4866*4882a593Smuzhiyun
4867*4882a593Smuzhiyun /* server pointer checked in called function,
4868*4882a593Smuzhiyun but should never be null here anyway */
4869*4882a593Smuzhiyun pSMB->hdr.Mid = get_next_mid(ses->server);
4870*4882a593Smuzhiyun pSMB->hdr.Tid = ses->tcon_ipc->tid;
4871*4882a593Smuzhiyun pSMB->hdr.Uid = ses->Suid;
4872*4882a593Smuzhiyun if (ses->capabilities & CAP_STATUS32)
4873*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4874*4882a593Smuzhiyun if (ses->capabilities & CAP_DFS)
4875*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_DFS;
4876*4882a593Smuzhiyun
4877*4882a593Smuzhiyun if (ses->capabilities & CAP_UNICODE) {
4878*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4879*4882a593Smuzhiyun name_len =
4880*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4881*4882a593Smuzhiyun search_name, PATH_MAX, nls_codepage,
4882*4882a593Smuzhiyun remap);
4883*4882a593Smuzhiyun name_len++; /* trailing null */
4884*4882a593Smuzhiyun name_len *= 2;
4885*4882a593Smuzhiyun } else { /* BB improve the check for buffer overruns BB */
4886*4882a593Smuzhiyun name_len = copy_path_name(pSMB->RequestFileName, search_name);
4887*4882a593Smuzhiyun }
4888*4882a593Smuzhiyun
4889*4882a593Smuzhiyun if (ses->server->sign)
4890*4882a593Smuzhiyun pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4891*4882a593Smuzhiyun
4892*4882a593Smuzhiyun pSMB->hdr.Uid = ses->Suid;
4893*4882a593Smuzhiyun
4894*4882a593Smuzhiyun params = 2 /* level */ + name_len /*includes null */ ;
4895*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
4896*4882a593Smuzhiyun pSMB->DataCount = 0;
4897*4882a593Smuzhiyun pSMB->DataOffset = 0;
4898*4882a593Smuzhiyun pSMB->MaxParameterCount = 0;
4899*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
4900*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4000);
4901*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4902*4882a593Smuzhiyun pSMB->Reserved = 0;
4903*4882a593Smuzhiyun pSMB->Flags = 0;
4904*4882a593Smuzhiyun pSMB->Timeout = 0;
4905*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4906*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
4907*4882a593Smuzhiyun struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
4908*4882a593Smuzhiyun pSMB->SetupCount = 1;
4909*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4910*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4911*4882a593Smuzhiyun byte_count = params + 3 /* pad */ ;
4912*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
4913*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
4914*4882a593Smuzhiyun pSMB->MaxReferralLevel = cpu_to_le16(3);
4915*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4916*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4917*4882a593Smuzhiyun
4918*4882a593Smuzhiyun rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4919*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4920*4882a593Smuzhiyun if (rc) {
4921*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
4922*4882a593Smuzhiyun goto GetDFSRefExit;
4923*4882a593Smuzhiyun }
4924*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4925*4882a593Smuzhiyun
4926*4882a593Smuzhiyun /* BB Also check if enough total bytes returned? */
4927*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 17) {
4928*4882a593Smuzhiyun rc = -EIO; /* bad smb */
4929*4882a593Smuzhiyun goto GetDFSRefExit;
4930*4882a593Smuzhiyun }
4931*4882a593Smuzhiyun
4932*4882a593Smuzhiyun cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4933*4882a593Smuzhiyun get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
4934*4882a593Smuzhiyun
4935*4882a593Smuzhiyun /* parse returned result into more usable form */
4936*4882a593Smuzhiyun rc = parse_dfs_referrals(&pSMBr->dfs_data,
4937*4882a593Smuzhiyun le16_to_cpu(pSMBr->t2.DataCount),
4938*4882a593Smuzhiyun num_of_nodes, target_nodes, nls_codepage,
4939*4882a593Smuzhiyun remap, search_name,
4940*4882a593Smuzhiyun (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
4941*4882a593Smuzhiyun
4942*4882a593Smuzhiyun GetDFSRefExit:
4943*4882a593Smuzhiyun cifs_buf_release(pSMB);
4944*4882a593Smuzhiyun
4945*4882a593Smuzhiyun if (rc == -EAGAIN)
4946*4882a593Smuzhiyun goto getDFSRetry;
4947*4882a593Smuzhiyun
4948*4882a593Smuzhiyun return rc;
4949*4882a593Smuzhiyun }
4950*4882a593Smuzhiyun
4951*4882a593Smuzhiyun /* Query File System Info such as free space to old servers such as Win 9x */
4952*4882a593Smuzhiyun int
SMBOldQFSInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)4953*4882a593Smuzhiyun SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4954*4882a593Smuzhiyun struct kstatfs *FSData)
4955*4882a593Smuzhiyun {
4956*4882a593Smuzhiyun /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4957*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
4958*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4959*4882a593Smuzhiyun FILE_SYSTEM_ALLOC_INFO *response_data;
4960*4882a593Smuzhiyun int rc = 0;
4961*4882a593Smuzhiyun int bytes_returned = 0;
4962*4882a593Smuzhiyun __u16 params, byte_count;
4963*4882a593Smuzhiyun
4964*4882a593Smuzhiyun cifs_dbg(FYI, "OldQFSInfo\n");
4965*4882a593Smuzhiyun oldQFSInfoRetry:
4966*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4967*4882a593Smuzhiyun (void **) &pSMBr);
4968*4882a593Smuzhiyun if (rc)
4969*4882a593Smuzhiyun return rc;
4970*4882a593Smuzhiyun
4971*4882a593Smuzhiyun params = 2; /* level */
4972*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
4973*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
4974*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
4975*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
4976*4882a593Smuzhiyun pSMB->Reserved = 0;
4977*4882a593Smuzhiyun pSMB->Flags = 0;
4978*4882a593Smuzhiyun pSMB->Timeout = 0;
4979*4882a593Smuzhiyun pSMB->Reserved2 = 0;
4980*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
4981*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
4982*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
4983*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
4984*4882a593Smuzhiyun struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4985*4882a593Smuzhiyun pSMB->DataCount = 0;
4986*4882a593Smuzhiyun pSMB->DataOffset = 0;
4987*4882a593Smuzhiyun pSMB->SetupCount = 1;
4988*4882a593Smuzhiyun pSMB->Reserved3 = 0;
4989*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4990*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4991*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
4992*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
4993*4882a593Smuzhiyun
4994*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4995*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4996*4882a593Smuzhiyun if (rc) {
4997*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
4998*4882a593Smuzhiyun } else { /* decode response */
4999*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5000*4882a593Smuzhiyun
5001*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 18)
5002*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5003*4882a593Smuzhiyun else {
5004*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5005*4882a593Smuzhiyun cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
5006*4882a593Smuzhiyun get_bcc(&pSMBr->hdr), data_offset);
5007*4882a593Smuzhiyun
5008*4882a593Smuzhiyun response_data = (FILE_SYSTEM_ALLOC_INFO *)
5009*4882a593Smuzhiyun (((char *) &pSMBr->hdr.Protocol) + data_offset);
5010*4882a593Smuzhiyun FSData->f_bsize =
5011*4882a593Smuzhiyun le16_to_cpu(response_data->BytesPerSector) *
5012*4882a593Smuzhiyun le32_to_cpu(response_data->
5013*4882a593Smuzhiyun SectorsPerAllocationUnit);
5014*4882a593Smuzhiyun /*
5015*4882a593Smuzhiyun * much prefer larger but if server doesn't report
5016*4882a593Smuzhiyun * a valid size than 4K is a reasonable minimum
5017*4882a593Smuzhiyun */
5018*4882a593Smuzhiyun if (FSData->f_bsize < 512)
5019*4882a593Smuzhiyun FSData->f_bsize = 4096;
5020*4882a593Smuzhiyun
5021*4882a593Smuzhiyun FSData->f_blocks =
5022*4882a593Smuzhiyun le32_to_cpu(response_data->TotalAllocationUnits);
5023*4882a593Smuzhiyun FSData->f_bfree = FSData->f_bavail =
5024*4882a593Smuzhiyun le32_to_cpu(response_data->FreeAllocationUnits);
5025*4882a593Smuzhiyun cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5026*4882a593Smuzhiyun (unsigned long long)FSData->f_blocks,
5027*4882a593Smuzhiyun (unsigned long long)FSData->f_bfree,
5028*4882a593Smuzhiyun FSData->f_bsize);
5029*4882a593Smuzhiyun }
5030*4882a593Smuzhiyun }
5031*4882a593Smuzhiyun cifs_buf_release(pSMB);
5032*4882a593Smuzhiyun
5033*4882a593Smuzhiyun if (rc == -EAGAIN)
5034*4882a593Smuzhiyun goto oldQFSInfoRetry;
5035*4882a593Smuzhiyun
5036*4882a593Smuzhiyun return rc;
5037*4882a593Smuzhiyun }
5038*4882a593Smuzhiyun
5039*4882a593Smuzhiyun int
CIFSSMBQFSInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)5040*4882a593Smuzhiyun CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5041*4882a593Smuzhiyun struct kstatfs *FSData)
5042*4882a593Smuzhiyun {
5043*4882a593Smuzhiyun /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5044*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
5045*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5046*4882a593Smuzhiyun FILE_SYSTEM_INFO *response_data;
5047*4882a593Smuzhiyun int rc = 0;
5048*4882a593Smuzhiyun int bytes_returned = 0;
5049*4882a593Smuzhiyun __u16 params, byte_count;
5050*4882a593Smuzhiyun
5051*4882a593Smuzhiyun cifs_dbg(FYI, "In QFSInfo\n");
5052*4882a593Smuzhiyun QFSInfoRetry:
5053*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5054*4882a593Smuzhiyun (void **) &pSMBr);
5055*4882a593Smuzhiyun if (rc)
5056*4882a593Smuzhiyun return rc;
5057*4882a593Smuzhiyun
5058*4882a593Smuzhiyun params = 2; /* level */
5059*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
5060*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5061*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5062*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5063*4882a593Smuzhiyun pSMB->Reserved = 0;
5064*4882a593Smuzhiyun pSMB->Flags = 0;
5065*4882a593Smuzhiyun pSMB->Timeout = 0;
5066*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5067*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
5068*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
5069*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
5070*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
5071*4882a593Smuzhiyun struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5072*4882a593Smuzhiyun pSMB->DataCount = 0;
5073*4882a593Smuzhiyun pSMB->DataOffset = 0;
5074*4882a593Smuzhiyun pSMB->SetupCount = 1;
5075*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5076*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5077*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
5078*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5079*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5080*4882a593Smuzhiyun
5081*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5082*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5083*4882a593Smuzhiyun if (rc) {
5084*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
5085*4882a593Smuzhiyun } else { /* decode response */
5086*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5087*4882a593Smuzhiyun
5088*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 24)
5089*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5090*4882a593Smuzhiyun else {
5091*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5092*4882a593Smuzhiyun
5093*4882a593Smuzhiyun response_data =
5094*4882a593Smuzhiyun (FILE_SYSTEM_INFO
5095*4882a593Smuzhiyun *) (((char *) &pSMBr->hdr.Protocol) +
5096*4882a593Smuzhiyun data_offset);
5097*4882a593Smuzhiyun FSData->f_bsize =
5098*4882a593Smuzhiyun le32_to_cpu(response_data->BytesPerSector) *
5099*4882a593Smuzhiyun le32_to_cpu(response_data->
5100*4882a593Smuzhiyun SectorsPerAllocationUnit);
5101*4882a593Smuzhiyun /*
5102*4882a593Smuzhiyun * much prefer larger but if server doesn't report
5103*4882a593Smuzhiyun * a valid size than 4K is a reasonable minimum
5104*4882a593Smuzhiyun */
5105*4882a593Smuzhiyun if (FSData->f_bsize < 512)
5106*4882a593Smuzhiyun FSData->f_bsize = 4096;
5107*4882a593Smuzhiyun
5108*4882a593Smuzhiyun FSData->f_blocks =
5109*4882a593Smuzhiyun le64_to_cpu(response_data->TotalAllocationUnits);
5110*4882a593Smuzhiyun FSData->f_bfree = FSData->f_bavail =
5111*4882a593Smuzhiyun le64_to_cpu(response_data->FreeAllocationUnits);
5112*4882a593Smuzhiyun cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5113*4882a593Smuzhiyun (unsigned long long)FSData->f_blocks,
5114*4882a593Smuzhiyun (unsigned long long)FSData->f_bfree,
5115*4882a593Smuzhiyun FSData->f_bsize);
5116*4882a593Smuzhiyun }
5117*4882a593Smuzhiyun }
5118*4882a593Smuzhiyun cifs_buf_release(pSMB);
5119*4882a593Smuzhiyun
5120*4882a593Smuzhiyun if (rc == -EAGAIN)
5121*4882a593Smuzhiyun goto QFSInfoRetry;
5122*4882a593Smuzhiyun
5123*4882a593Smuzhiyun return rc;
5124*4882a593Smuzhiyun }
5125*4882a593Smuzhiyun
5126*4882a593Smuzhiyun int
CIFSSMBQFSAttributeInfo(const unsigned int xid,struct cifs_tcon * tcon)5127*4882a593Smuzhiyun CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
5128*4882a593Smuzhiyun {
5129*4882a593Smuzhiyun /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5130*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
5131*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5132*4882a593Smuzhiyun FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5133*4882a593Smuzhiyun int rc = 0;
5134*4882a593Smuzhiyun int bytes_returned = 0;
5135*4882a593Smuzhiyun __u16 params, byte_count;
5136*4882a593Smuzhiyun
5137*4882a593Smuzhiyun cifs_dbg(FYI, "In QFSAttributeInfo\n");
5138*4882a593Smuzhiyun QFSAttributeRetry:
5139*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5140*4882a593Smuzhiyun (void **) &pSMBr);
5141*4882a593Smuzhiyun if (rc)
5142*4882a593Smuzhiyun return rc;
5143*4882a593Smuzhiyun
5144*4882a593Smuzhiyun params = 2; /* level */
5145*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
5146*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5147*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5148*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5149*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5150*4882a593Smuzhiyun pSMB->Reserved = 0;
5151*4882a593Smuzhiyun pSMB->Flags = 0;
5152*4882a593Smuzhiyun pSMB->Timeout = 0;
5153*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5154*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
5155*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
5156*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
5157*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
5158*4882a593Smuzhiyun struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5159*4882a593Smuzhiyun pSMB->DataCount = 0;
5160*4882a593Smuzhiyun pSMB->DataOffset = 0;
5161*4882a593Smuzhiyun pSMB->SetupCount = 1;
5162*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5163*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5164*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5165*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5166*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5167*4882a593Smuzhiyun
5168*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5169*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5170*4882a593Smuzhiyun if (rc) {
5171*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
5172*4882a593Smuzhiyun } else { /* decode response */
5173*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5174*4882a593Smuzhiyun
5175*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 13) {
5176*4882a593Smuzhiyun /* BB also check if enough bytes returned */
5177*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5178*4882a593Smuzhiyun } else {
5179*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5180*4882a593Smuzhiyun response_data =
5181*4882a593Smuzhiyun (FILE_SYSTEM_ATTRIBUTE_INFO
5182*4882a593Smuzhiyun *) (((char *) &pSMBr->hdr.Protocol) +
5183*4882a593Smuzhiyun data_offset);
5184*4882a593Smuzhiyun memcpy(&tcon->fsAttrInfo, response_data,
5185*4882a593Smuzhiyun sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
5186*4882a593Smuzhiyun }
5187*4882a593Smuzhiyun }
5188*4882a593Smuzhiyun cifs_buf_release(pSMB);
5189*4882a593Smuzhiyun
5190*4882a593Smuzhiyun if (rc == -EAGAIN)
5191*4882a593Smuzhiyun goto QFSAttributeRetry;
5192*4882a593Smuzhiyun
5193*4882a593Smuzhiyun return rc;
5194*4882a593Smuzhiyun }
5195*4882a593Smuzhiyun
5196*4882a593Smuzhiyun int
CIFSSMBQFSDeviceInfo(const unsigned int xid,struct cifs_tcon * tcon)5197*4882a593Smuzhiyun CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
5198*4882a593Smuzhiyun {
5199*4882a593Smuzhiyun /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5200*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
5201*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5202*4882a593Smuzhiyun FILE_SYSTEM_DEVICE_INFO *response_data;
5203*4882a593Smuzhiyun int rc = 0;
5204*4882a593Smuzhiyun int bytes_returned = 0;
5205*4882a593Smuzhiyun __u16 params, byte_count;
5206*4882a593Smuzhiyun
5207*4882a593Smuzhiyun cifs_dbg(FYI, "In QFSDeviceInfo\n");
5208*4882a593Smuzhiyun QFSDeviceRetry:
5209*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5210*4882a593Smuzhiyun (void **) &pSMBr);
5211*4882a593Smuzhiyun if (rc)
5212*4882a593Smuzhiyun return rc;
5213*4882a593Smuzhiyun
5214*4882a593Smuzhiyun params = 2; /* level */
5215*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
5216*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5217*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5218*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5219*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5220*4882a593Smuzhiyun pSMB->Reserved = 0;
5221*4882a593Smuzhiyun pSMB->Flags = 0;
5222*4882a593Smuzhiyun pSMB->Timeout = 0;
5223*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5224*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
5225*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
5226*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
5227*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
5228*4882a593Smuzhiyun struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5229*4882a593Smuzhiyun
5230*4882a593Smuzhiyun pSMB->DataCount = 0;
5231*4882a593Smuzhiyun pSMB->DataOffset = 0;
5232*4882a593Smuzhiyun pSMB->SetupCount = 1;
5233*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5234*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5235*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5236*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5237*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5238*4882a593Smuzhiyun
5239*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5240*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5241*4882a593Smuzhiyun if (rc) {
5242*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
5243*4882a593Smuzhiyun } else { /* decode response */
5244*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5245*4882a593Smuzhiyun
5246*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) <
5247*4882a593Smuzhiyun sizeof(FILE_SYSTEM_DEVICE_INFO))
5248*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5249*4882a593Smuzhiyun else {
5250*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5251*4882a593Smuzhiyun response_data =
5252*4882a593Smuzhiyun (FILE_SYSTEM_DEVICE_INFO *)
5253*4882a593Smuzhiyun (((char *) &pSMBr->hdr.Protocol) +
5254*4882a593Smuzhiyun data_offset);
5255*4882a593Smuzhiyun memcpy(&tcon->fsDevInfo, response_data,
5256*4882a593Smuzhiyun sizeof(FILE_SYSTEM_DEVICE_INFO));
5257*4882a593Smuzhiyun }
5258*4882a593Smuzhiyun }
5259*4882a593Smuzhiyun cifs_buf_release(pSMB);
5260*4882a593Smuzhiyun
5261*4882a593Smuzhiyun if (rc == -EAGAIN)
5262*4882a593Smuzhiyun goto QFSDeviceRetry;
5263*4882a593Smuzhiyun
5264*4882a593Smuzhiyun return rc;
5265*4882a593Smuzhiyun }
5266*4882a593Smuzhiyun
5267*4882a593Smuzhiyun int
CIFSSMBQFSUnixInfo(const unsigned int xid,struct cifs_tcon * tcon)5268*4882a593Smuzhiyun CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
5269*4882a593Smuzhiyun {
5270*4882a593Smuzhiyun /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5271*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
5272*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5273*4882a593Smuzhiyun FILE_SYSTEM_UNIX_INFO *response_data;
5274*4882a593Smuzhiyun int rc = 0;
5275*4882a593Smuzhiyun int bytes_returned = 0;
5276*4882a593Smuzhiyun __u16 params, byte_count;
5277*4882a593Smuzhiyun
5278*4882a593Smuzhiyun cifs_dbg(FYI, "In QFSUnixInfo\n");
5279*4882a593Smuzhiyun QFSUnixRetry:
5280*4882a593Smuzhiyun rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5281*4882a593Smuzhiyun (void **) &pSMB, (void **) &pSMBr);
5282*4882a593Smuzhiyun if (rc)
5283*4882a593Smuzhiyun return rc;
5284*4882a593Smuzhiyun
5285*4882a593Smuzhiyun params = 2; /* level */
5286*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
5287*4882a593Smuzhiyun pSMB->DataCount = 0;
5288*4882a593Smuzhiyun pSMB->DataOffset = 0;
5289*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5290*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5291*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(100);
5292*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5293*4882a593Smuzhiyun pSMB->Reserved = 0;
5294*4882a593Smuzhiyun pSMB->Flags = 0;
5295*4882a593Smuzhiyun pSMB->Timeout = 0;
5296*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5297*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
5298*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5299*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5300*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5301*4882a593Smuzhiyun smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5302*4882a593Smuzhiyun pSMB->SetupCount = 1;
5303*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5304*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5305*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5306*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5307*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5308*4882a593Smuzhiyun
5309*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5310*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5311*4882a593Smuzhiyun if (rc) {
5312*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
5313*4882a593Smuzhiyun } else { /* decode response */
5314*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5315*4882a593Smuzhiyun
5316*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 13) {
5317*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5318*4882a593Smuzhiyun } else {
5319*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5320*4882a593Smuzhiyun response_data =
5321*4882a593Smuzhiyun (FILE_SYSTEM_UNIX_INFO
5322*4882a593Smuzhiyun *) (((char *) &pSMBr->hdr.Protocol) +
5323*4882a593Smuzhiyun data_offset);
5324*4882a593Smuzhiyun memcpy(&tcon->fsUnixInfo, response_data,
5325*4882a593Smuzhiyun sizeof(FILE_SYSTEM_UNIX_INFO));
5326*4882a593Smuzhiyun }
5327*4882a593Smuzhiyun }
5328*4882a593Smuzhiyun cifs_buf_release(pSMB);
5329*4882a593Smuzhiyun
5330*4882a593Smuzhiyun if (rc == -EAGAIN)
5331*4882a593Smuzhiyun goto QFSUnixRetry;
5332*4882a593Smuzhiyun
5333*4882a593Smuzhiyun
5334*4882a593Smuzhiyun return rc;
5335*4882a593Smuzhiyun }
5336*4882a593Smuzhiyun
5337*4882a593Smuzhiyun int
CIFSSMBSetFSUnixInfo(const unsigned int xid,struct cifs_tcon * tcon,__u64 cap)5338*4882a593Smuzhiyun CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
5339*4882a593Smuzhiyun {
5340*4882a593Smuzhiyun /* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5341*4882a593Smuzhiyun TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5342*4882a593Smuzhiyun TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5343*4882a593Smuzhiyun int rc = 0;
5344*4882a593Smuzhiyun int bytes_returned = 0;
5345*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count;
5346*4882a593Smuzhiyun
5347*4882a593Smuzhiyun cifs_dbg(FYI, "In SETFSUnixInfo\n");
5348*4882a593Smuzhiyun SETFSUnixRetry:
5349*4882a593Smuzhiyun /* BB switch to small buf init to save memory */
5350*4882a593Smuzhiyun rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5351*4882a593Smuzhiyun (void **) &pSMB, (void **) &pSMBr);
5352*4882a593Smuzhiyun if (rc)
5353*4882a593Smuzhiyun return rc;
5354*4882a593Smuzhiyun
5355*4882a593Smuzhiyun params = 4; /* 2 bytes zero followed by info level. */
5356*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5357*4882a593Smuzhiyun pSMB->Reserved = 0;
5358*4882a593Smuzhiyun pSMB->Flags = 0;
5359*4882a593Smuzhiyun pSMB->Timeout = 0;
5360*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5361*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5362*4882a593Smuzhiyun - 4;
5363*4882a593Smuzhiyun offset = param_offset + params;
5364*4882a593Smuzhiyun
5365*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(4);
5366*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5367*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(100);
5368*4882a593Smuzhiyun pSMB->SetupCount = 1;
5369*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5370*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5371*4882a593Smuzhiyun byte_count = 1 /* pad */ + params + 12;
5372*4882a593Smuzhiyun
5373*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(12);
5374*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5375*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5376*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5377*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5378*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5379*4882a593Smuzhiyun
5380*4882a593Smuzhiyun /* Params. */
5381*4882a593Smuzhiyun pSMB->FileNum = 0;
5382*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5383*4882a593Smuzhiyun
5384*4882a593Smuzhiyun /* Data. */
5385*4882a593Smuzhiyun pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5386*4882a593Smuzhiyun pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5387*4882a593Smuzhiyun pSMB->ClientUnixCap = cpu_to_le64(cap);
5388*4882a593Smuzhiyun
5389*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5390*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5391*4882a593Smuzhiyun
5392*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5393*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5394*4882a593Smuzhiyun if (rc) {
5395*4882a593Smuzhiyun cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
5396*4882a593Smuzhiyun } else { /* decode response */
5397*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5398*4882a593Smuzhiyun if (rc)
5399*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5400*4882a593Smuzhiyun }
5401*4882a593Smuzhiyun cifs_buf_release(pSMB);
5402*4882a593Smuzhiyun
5403*4882a593Smuzhiyun if (rc == -EAGAIN)
5404*4882a593Smuzhiyun goto SETFSUnixRetry;
5405*4882a593Smuzhiyun
5406*4882a593Smuzhiyun return rc;
5407*4882a593Smuzhiyun }
5408*4882a593Smuzhiyun
5409*4882a593Smuzhiyun
5410*4882a593Smuzhiyun
5411*4882a593Smuzhiyun int
CIFSSMBQFSPosixInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)5412*4882a593Smuzhiyun CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
5413*4882a593Smuzhiyun struct kstatfs *FSData)
5414*4882a593Smuzhiyun {
5415*4882a593Smuzhiyun /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5416*4882a593Smuzhiyun TRANSACTION2_QFSI_REQ *pSMB = NULL;
5417*4882a593Smuzhiyun TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5418*4882a593Smuzhiyun FILE_SYSTEM_POSIX_INFO *response_data;
5419*4882a593Smuzhiyun int rc = 0;
5420*4882a593Smuzhiyun int bytes_returned = 0;
5421*4882a593Smuzhiyun __u16 params, byte_count;
5422*4882a593Smuzhiyun
5423*4882a593Smuzhiyun cifs_dbg(FYI, "In QFSPosixInfo\n");
5424*4882a593Smuzhiyun QFSPosixRetry:
5425*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5426*4882a593Smuzhiyun (void **) &pSMBr);
5427*4882a593Smuzhiyun if (rc)
5428*4882a593Smuzhiyun return rc;
5429*4882a593Smuzhiyun
5430*4882a593Smuzhiyun params = 2; /* level */
5431*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
5432*4882a593Smuzhiyun pSMB->DataCount = 0;
5433*4882a593Smuzhiyun pSMB->DataOffset = 0;
5434*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5435*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5436*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(100);
5437*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5438*4882a593Smuzhiyun pSMB->Reserved = 0;
5439*4882a593Smuzhiyun pSMB->Flags = 0;
5440*4882a593Smuzhiyun pSMB->Timeout = 0;
5441*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5442*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
5443*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5444*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5445*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5446*4882a593Smuzhiyun smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5447*4882a593Smuzhiyun pSMB->SetupCount = 1;
5448*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5449*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5450*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5451*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5452*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5453*4882a593Smuzhiyun
5454*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5455*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5456*4882a593Smuzhiyun if (rc) {
5457*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
5458*4882a593Smuzhiyun } else { /* decode response */
5459*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5460*4882a593Smuzhiyun
5461*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 13) {
5462*4882a593Smuzhiyun rc = -EIO; /* bad smb */
5463*4882a593Smuzhiyun } else {
5464*4882a593Smuzhiyun __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5465*4882a593Smuzhiyun response_data =
5466*4882a593Smuzhiyun (FILE_SYSTEM_POSIX_INFO
5467*4882a593Smuzhiyun *) (((char *) &pSMBr->hdr.Protocol) +
5468*4882a593Smuzhiyun data_offset);
5469*4882a593Smuzhiyun FSData->f_bsize =
5470*4882a593Smuzhiyun le32_to_cpu(response_data->BlockSize);
5471*4882a593Smuzhiyun /*
5472*4882a593Smuzhiyun * much prefer larger but if server doesn't report
5473*4882a593Smuzhiyun * a valid size than 4K is a reasonable minimum
5474*4882a593Smuzhiyun */
5475*4882a593Smuzhiyun if (FSData->f_bsize < 512)
5476*4882a593Smuzhiyun FSData->f_bsize = 4096;
5477*4882a593Smuzhiyun
5478*4882a593Smuzhiyun FSData->f_blocks =
5479*4882a593Smuzhiyun le64_to_cpu(response_data->TotalBlocks);
5480*4882a593Smuzhiyun FSData->f_bfree =
5481*4882a593Smuzhiyun le64_to_cpu(response_data->BlocksAvail);
5482*4882a593Smuzhiyun if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
5483*4882a593Smuzhiyun FSData->f_bavail = FSData->f_bfree;
5484*4882a593Smuzhiyun } else {
5485*4882a593Smuzhiyun FSData->f_bavail =
5486*4882a593Smuzhiyun le64_to_cpu(response_data->UserBlocksAvail);
5487*4882a593Smuzhiyun }
5488*4882a593Smuzhiyun if (response_data->TotalFileNodes != cpu_to_le64(-1))
5489*4882a593Smuzhiyun FSData->f_files =
5490*4882a593Smuzhiyun le64_to_cpu(response_data->TotalFileNodes);
5491*4882a593Smuzhiyun if (response_data->FreeFileNodes != cpu_to_le64(-1))
5492*4882a593Smuzhiyun FSData->f_ffree =
5493*4882a593Smuzhiyun le64_to_cpu(response_data->FreeFileNodes);
5494*4882a593Smuzhiyun }
5495*4882a593Smuzhiyun }
5496*4882a593Smuzhiyun cifs_buf_release(pSMB);
5497*4882a593Smuzhiyun
5498*4882a593Smuzhiyun if (rc == -EAGAIN)
5499*4882a593Smuzhiyun goto QFSPosixRetry;
5500*4882a593Smuzhiyun
5501*4882a593Smuzhiyun return rc;
5502*4882a593Smuzhiyun }
5503*4882a593Smuzhiyun
5504*4882a593Smuzhiyun
5505*4882a593Smuzhiyun /*
5506*4882a593Smuzhiyun * We can not use write of zero bytes trick to set file size due to need for
5507*4882a593Smuzhiyun * large file support. Also note that this SetPathInfo is preferred to
5508*4882a593Smuzhiyun * SetFileInfo based method in next routine which is only needed to work around
5509*4882a593Smuzhiyun * a sharing violation bugin Samba which this routine can run into.
5510*4882a593Smuzhiyun */
5511*4882a593Smuzhiyun int
CIFSSMBSetEOF(const unsigned int xid,struct cifs_tcon * tcon,const char * file_name,__u64 size,struct cifs_sb_info * cifs_sb,bool set_allocation)5512*4882a593Smuzhiyun CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5513*4882a593Smuzhiyun const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5514*4882a593Smuzhiyun bool set_allocation)
5515*4882a593Smuzhiyun {
5516*4882a593Smuzhiyun struct smb_com_transaction2_spi_req *pSMB = NULL;
5517*4882a593Smuzhiyun struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5518*4882a593Smuzhiyun struct file_end_of_file_info *parm_data;
5519*4882a593Smuzhiyun int name_len;
5520*4882a593Smuzhiyun int rc = 0;
5521*4882a593Smuzhiyun int bytes_returned = 0;
5522*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
5523*4882a593Smuzhiyun
5524*4882a593Smuzhiyun __u16 params, byte_count, data_count, param_offset, offset;
5525*4882a593Smuzhiyun
5526*4882a593Smuzhiyun cifs_dbg(FYI, "In SetEOF\n");
5527*4882a593Smuzhiyun SetEOFRetry:
5528*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5529*4882a593Smuzhiyun (void **) &pSMBr);
5530*4882a593Smuzhiyun if (rc)
5531*4882a593Smuzhiyun return rc;
5532*4882a593Smuzhiyun
5533*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5534*4882a593Smuzhiyun name_len =
5535*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5536*4882a593Smuzhiyun PATH_MAX, cifs_sb->local_nls, remap);
5537*4882a593Smuzhiyun name_len++; /* trailing null */
5538*4882a593Smuzhiyun name_len *= 2;
5539*4882a593Smuzhiyun } else {
5540*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, file_name);
5541*4882a593Smuzhiyun }
5542*4882a593Smuzhiyun params = 6 + name_len;
5543*4882a593Smuzhiyun data_count = sizeof(struct file_end_of_file_info);
5544*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5545*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(4100);
5546*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5547*4882a593Smuzhiyun pSMB->Reserved = 0;
5548*4882a593Smuzhiyun pSMB->Flags = 0;
5549*4882a593Smuzhiyun pSMB->Timeout = 0;
5550*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5551*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
5552*4882a593Smuzhiyun InformationLevel) - 4;
5553*4882a593Smuzhiyun offset = param_offset + params;
5554*4882a593Smuzhiyun if (set_allocation) {
5555*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5556*4882a593Smuzhiyun pSMB->InformationLevel =
5557*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5558*4882a593Smuzhiyun else
5559*4882a593Smuzhiyun pSMB->InformationLevel =
5560*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5561*4882a593Smuzhiyun } else /* Set File Size */ {
5562*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5563*4882a593Smuzhiyun pSMB->InformationLevel =
5564*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5565*4882a593Smuzhiyun else
5566*4882a593Smuzhiyun pSMB->InformationLevel =
5567*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5568*4882a593Smuzhiyun }
5569*4882a593Smuzhiyun
5570*4882a593Smuzhiyun parm_data =
5571*4882a593Smuzhiyun (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5572*4882a593Smuzhiyun offset);
5573*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5574*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5575*4882a593Smuzhiyun pSMB->SetupCount = 1;
5576*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5577*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5578*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + data_count;
5579*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(data_count);
5580*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5581*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5582*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5583*4882a593Smuzhiyun pSMB->Reserved4 = 0;
5584*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5585*4882a593Smuzhiyun parm_data->FileSize = cpu_to_le64(size);
5586*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5587*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5588*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5589*4882a593Smuzhiyun if (rc)
5590*4882a593Smuzhiyun cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
5591*4882a593Smuzhiyun
5592*4882a593Smuzhiyun cifs_buf_release(pSMB);
5593*4882a593Smuzhiyun
5594*4882a593Smuzhiyun if (rc == -EAGAIN)
5595*4882a593Smuzhiyun goto SetEOFRetry;
5596*4882a593Smuzhiyun
5597*4882a593Smuzhiyun return rc;
5598*4882a593Smuzhiyun }
5599*4882a593Smuzhiyun
5600*4882a593Smuzhiyun int
CIFSSMBSetFileSize(const unsigned int xid,struct cifs_tcon * tcon,struct cifsFileInfo * cfile,__u64 size,bool set_allocation)5601*4882a593Smuzhiyun CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5602*4882a593Smuzhiyun struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
5603*4882a593Smuzhiyun {
5604*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
5605*4882a593Smuzhiyun struct file_end_of_file_info *parm_data;
5606*4882a593Smuzhiyun int rc = 0;
5607*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
5608*4882a593Smuzhiyun
5609*4882a593Smuzhiyun cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5610*4882a593Smuzhiyun (long long)size);
5611*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5612*4882a593Smuzhiyun
5613*4882a593Smuzhiyun if (rc)
5614*4882a593Smuzhiyun return rc;
5615*4882a593Smuzhiyun
5616*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5617*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
5618*4882a593Smuzhiyun
5619*4882a593Smuzhiyun params = 6;
5620*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5621*4882a593Smuzhiyun pSMB->Reserved = 0;
5622*4882a593Smuzhiyun pSMB->Flags = 0;
5623*4882a593Smuzhiyun pSMB->Timeout = 0;
5624*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5625*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5626*4882a593Smuzhiyun offset = param_offset + params;
5627*4882a593Smuzhiyun
5628*4882a593Smuzhiyun count = sizeof(struct file_end_of_file_info);
5629*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5630*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
5631*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5632*4882a593Smuzhiyun pSMB->SetupCount = 1;
5633*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5634*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5635*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
5636*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
5637*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5638*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5639*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5640*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5641*4882a593Smuzhiyun parm_data =
5642*4882a593Smuzhiyun (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5643*4882a593Smuzhiyun + offset);
5644*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5645*4882a593Smuzhiyun parm_data->FileSize = cpu_to_le64(size);
5646*4882a593Smuzhiyun pSMB->Fid = cfile->fid.netfid;
5647*4882a593Smuzhiyun if (set_allocation) {
5648*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5649*4882a593Smuzhiyun pSMB->InformationLevel =
5650*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5651*4882a593Smuzhiyun else
5652*4882a593Smuzhiyun pSMB->InformationLevel =
5653*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5654*4882a593Smuzhiyun } else /* Set File Size */ {
5655*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5656*4882a593Smuzhiyun pSMB->InformationLevel =
5657*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
5658*4882a593Smuzhiyun else
5659*4882a593Smuzhiyun pSMB->InformationLevel =
5660*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
5661*4882a593Smuzhiyun }
5662*4882a593Smuzhiyun pSMB->Reserved4 = 0;
5663*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5664*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5665*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5666*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
5667*4882a593Smuzhiyun if (rc) {
5668*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5669*4882a593Smuzhiyun rc);
5670*4882a593Smuzhiyun }
5671*4882a593Smuzhiyun
5672*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
5673*4882a593Smuzhiyun since file handle passed in no longer valid */
5674*4882a593Smuzhiyun
5675*4882a593Smuzhiyun return rc;
5676*4882a593Smuzhiyun }
5677*4882a593Smuzhiyun
5678*4882a593Smuzhiyun /* Some legacy servers such as NT4 require that the file times be set on
5679*4882a593Smuzhiyun an open handle, rather than by pathname - this is awkward due to
5680*4882a593Smuzhiyun potential access conflicts on the open, but it is unavoidable for these
5681*4882a593Smuzhiyun old servers since the only other choice is to go from 100 nanosecond DCE
5682*4882a593Smuzhiyun time and resort to the original setpathinfo level which takes the ancient
5683*4882a593Smuzhiyun DOS time format with 2 second granularity */
5684*4882a593Smuzhiyun int
CIFSSMBSetFileInfo(const unsigned int xid,struct cifs_tcon * tcon,const FILE_BASIC_INFO * data,__u16 fid,__u32 pid_of_opener)5685*4882a593Smuzhiyun CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5686*4882a593Smuzhiyun const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
5687*4882a593Smuzhiyun {
5688*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
5689*4882a593Smuzhiyun char *data_offset;
5690*4882a593Smuzhiyun int rc = 0;
5691*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
5692*4882a593Smuzhiyun
5693*4882a593Smuzhiyun cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
5694*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5695*4882a593Smuzhiyun
5696*4882a593Smuzhiyun if (rc)
5697*4882a593Smuzhiyun return rc;
5698*4882a593Smuzhiyun
5699*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5700*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5701*4882a593Smuzhiyun
5702*4882a593Smuzhiyun params = 6;
5703*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5704*4882a593Smuzhiyun pSMB->Reserved = 0;
5705*4882a593Smuzhiyun pSMB->Flags = 0;
5706*4882a593Smuzhiyun pSMB->Timeout = 0;
5707*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5708*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5709*4882a593Smuzhiyun offset = param_offset + params;
5710*4882a593Smuzhiyun
5711*4882a593Smuzhiyun data_offset = (char *)pSMB +
5712*4882a593Smuzhiyun offsetof(struct smb_hdr, Protocol) + offset;
5713*4882a593Smuzhiyun
5714*4882a593Smuzhiyun count = sizeof(FILE_BASIC_INFO);
5715*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5716*4882a593Smuzhiyun /* BB find max SMB PDU from sess */
5717*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5718*4882a593Smuzhiyun pSMB->SetupCount = 1;
5719*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5720*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5721*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
5722*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
5723*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5724*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5725*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5726*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5727*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5728*4882a593Smuzhiyun pSMB->Fid = fid;
5729*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5730*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5731*4882a593Smuzhiyun else
5732*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5733*4882a593Smuzhiyun pSMB->Reserved4 = 0;
5734*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5735*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5736*4882a593Smuzhiyun memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5737*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5738*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
5739*4882a593Smuzhiyun if (rc)
5740*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5741*4882a593Smuzhiyun rc);
5742*4882a593Smuzhiyun
5743*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
5744*4882a593Smuzhiyun since file handle passed in no longer valid */
5745*4882a593Smuzhiyun
5746*4882a593Smuzhiyun return rc;
5747*4882a593Smuzhiyun }
5748*4882a593Smuzhiyun
5749*4882a593Smuzhiyun int
CIFSSMBSetFileDisposition(const unsigned int xid,struct cifs_tcon * tcon,bool delete_file,__u16 fid,__u32 pid_of_opener)5750*4882a593Smuzhiyun CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
5751*4882a593Smuzhiyun bool delete_file, __u16 fid, __u32 pid_of_opener)
5752*4882a593Smuzhiyun {
5753*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
5754*4882a593Smuzhiyun char *data_offset;
5755*4882a593Smuzhiyun int rc = 0;
5756*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
5757*4882a593Smuzhiyun
5758*4882a593Smuzhiyun cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
5759*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5760*4882a593Smuzhiyun
5761*4882a593Smuzhiyun if (rc)
5762*4882a593Smuzhiyun return rc;
5763*4882a593Smuzhiyun
5764*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5765*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5766*4882a593Smuzhiyun
5767*4882a593Smuzhiyun params = 6;
5768*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5769*4882a593Smuzhiyun pSMB->Reserved = 0;
5770*4882a593Smuzhiyun pSMB->Flags = 0;
5771*4882a593Smuzhiyun pSMB->Timeout = 0;
5772*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5773*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5774*4882a593Smuzhiyun offset = param_offset + params;
5775*4882a593Smuzhiyun
5776*4882a593Smuzhiyun data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5777*4882a593Smuzhiyun
5778*4882a593Smuzhiyun count = 1;
5779*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5780*4882a593Smuzhiyun /* BB find max SMB PDU from sess */
5781*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5782*4882a593Smuzhiyun pSMB->SetupCount = 1;
5783*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5784*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5785*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
5786*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
5787*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5788*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5789*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5790*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5791*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5792*4882a593Smuzhiyun pSMB->Fid = fid;
5793*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5794*4882a593Smuzhiyun pSMB->Reserved4 = 0;
5795*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5796*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5797*4882a593Smuzhiyun *data_offset = delete_file ? 1 : 0;
5798*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5799*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
5800*4882a593Smuzhiyun if (rc)
5801*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
5802*4882a593Smuzhiyun
5803*4882a593Smuzhiyun return rc;
5804*4882a593Smuzhiyun }
5805*4882a593Smuzhiyun
5806*4882a593Smuzhiyun static int
CIFSSMBSetPathInfoFB(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const FILE_BASIC_INFO * data,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)5807*4882a593Smuzhiyun CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
5808*4882a593Smuzhiyun const char *fileName, const FILE_BASIC_INFO *data,
5809*4882a593Smuzhiyun const struct nls_table *nls_codepage,
5810*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
5811*4882a593Smuzhiyun {
5812*4882a593Smuzhiyun int oplock = 0;
5813*4882a593Smuzhiyun struct cifs_open_parms oparms;
5814*4882a593Smuzhiyun struct cifs_fid fid;
5815*4882a593Smuzhiyun int rc;
5816*4882a593Smuzhiyun
5817*4882a593Smuzhiyun oparms.tcon = tcon;
5818*4882a593Smuzhiyun oparms.cifs_sb = cifs_sb;
5819*4882a593Smuzhiyun oparms.desired_access = GENERIC_WRITE;
5820*4882a593Smuzhiyun oparms.create_options = cifs_create_options(cifs_sb, 0);
5821*4882a593Smuzhiyun oparms.disposition = FILE_OPEN;
5822*4882a593Smuzhiyun oparms.path = fileName;
5823*4882a593Smuzhiyun oparms.fid = &fid;
5824*4882a593Smuzhiyun oparms.reconnect = false;
5825*4882a593Smuzhiyun
5826*4882a593Smuzhiyun rc = CIFS_open(xid, &oparms, &oplock, NULL);
5827*4882a593Smuzhiyun if (rc)
5828*4882a593Smuzhiyun goto out;
5829*4882a593Smuzhiyun
5830*4882a593Smuzhiyun rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
5831*4882a593Smuzhiyun CIFSSMBClose(xid, tcon, fid.netfid);
5832*4882a593Smuzhiyun out:
5833*4882a593Smuzhiyun
5834*4882a593Smuzhiyun return rc;
5835*4882a593Smuzhiyun }
5836*4882a593Smuzhiyun
5837*4882a593Smuzhiyun int
CIFSSMBSetPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const FILE_BASIC_INFO * data,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)5838*4882a593Smuzhiyun CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5839*4882a593Smuzhiyun const char *fileName, const FILE_BASIC_INFO *data,
5840*4882a593Smuzhiyun const struct nls_table *nls_codepage,
5841*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
5842*4882a593Smuzhiyun {
5843*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
5844*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
5845*4882a593Smuzhiyun int name_len;
5846*4882a593Smuzhiyun int rc = 0;
5847*4882a593Smuzhiyun int bytes_returned = 0;
5848*4882a593Smuzhiyun char *data_offset;
5849*4882a593Smuzhiyun __u16 params, param_offset, offset, byte_count, count;
5850*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
5851*4882a593Smuzhiyun
5852*4882a593Smuzhiyun cifs_dbg(FYI, "In SetTimes\n");
5853*4882a593Smuzhiyun
5854*4882a593Smuzhiyun SetTimesRetry:
5855*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5856*4882a593Smuzhiyun (void **) &pSMBr);
5857*4882a593Smuzhiyun if (rc)
5858*4882a593Smuzhiyun return rc;
5859*4882a593Smuzhiyun
5860*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5861*4882a593Smuzhiyun name_len =
5862*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5863*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
5864*4882a593Smuzhiyun name_len++; /* trailing null */
5865*4882a593Smuzhiyun name_len *= 2;
5866*4882a593Smuzhiyun } else {
5867*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, fileName);
5868*4882a593Smuzhiyun }
5869*4882a593Smuzhiyun
5870*4882a593Smuzhiyun params = 6 + name_len;
5871*4882a593Smuzhiyun count = sizeof(FILE_BASIC_INFO);
5872*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
5873*4882a593Smuzhiyun /* BB find max SMB PDU from sess structure BB */
5874*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
5875*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
5876*4882a593Smuzhiyun pSMB->Reserved = 0;
5877*4882a593Smuzhiyun pSMB->Flags = 0;
5878*4882a593Smuzhiyun pSMB->Timeout = 0;
5879*4882a593Smuzhiyun pSMB->Reserved2 = 0;
5880*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
5881*4882a593Smuzhiyun InformationLevel) - 4;
5882*4882a593Smuzhiyun offset = param_offset + params;
5883*4882a593Smuzhiyun data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5884*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
5885*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
5886*4882a593Smuzhiyun pSMB->SetupCount = 1;
5887*4882a593Smuzhiyun pSMB->Reserved3 = 0;
5888*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5889*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
5890*4882a593Smuzhiyun
5891*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
5892*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
5893*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
5894*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
5895*4882a593Smuzhiyun if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5896*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5897*4882a593Smuzhiyun else
5898*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5899*4882a593Smuzhiyun pSMB->Reserved4 = 0;
5900*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
5901*4882a593Smuzhiyun memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5902*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
5903*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5904*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5905*4882a593Smuzhiyun if (rc)
5906*4882a593Smuzhiyun cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
5907*4882a593Smuzhiyun
5908*4882a593Smuzhiyun cifs_buf_release(pSMB);
5909*4882a593Smuzhiyun
5910*4882a593Smuzhiyun if (rc == -EAGAIN)
5911*4882a593Smuzhiyun goto SetTimesRetry;
5912*4882a593Smuzhiyun
5913*4882a593Smuzhiyun if (rc == -EOPNOTSUPP)
5914*4882a593Smuzhiyun return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
5915*4882a593Smuzhiyun nls_codepage, cifs_sb);
5916*4882a593Smuzhiyun
5917*4882a593Smuzhiyun return rc;
5918*4882a593Smuzhiyun }
5919*4882a593Smuzhiyun
5920*4882a593Smuzhiyun /* Can not be used to set time stamps yet (due to old DOS time format) */
5921*4882a593Smuzhiyun /* Can be used to set attributes */
5922*4882a593Smuzhiyun #if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5923*4882a593Smuzhiyun handling it anyway and NT4 was what we thought it would be needed for
5924*4882a593Smuzhiyun Do not delete it until we prove whether needed for Win9x though */
5925*4882a593Smuzhiyun int
5926*4882a593Smuzhiyun CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
5927*4882a593Smuzhiyun __u16 dos_attrs, const struct nls_table *nls_codepage)
5928*4882a593Smuzhiyun {
5929*4882a593Smuzhiyun SETATTR_REQ *pSMB = NULL;
5930*4882a593Smuzhiyun SETATTR_RSP *pSMBr = NULL;
5931*4882a593Smuzhiyun int rc = 0;
5932*4882a593Smuzhiyun int bytes_returned;
5933*4882a593Smuzhiyun int name_len;
5934*4882a593Smuzhiyun
5935*4882a593Smuzhiyun cifs_dbg(FYI, "In SetAttrLegacy\n");
5936*4882a593Smuzhiyun
5937*4882a593Smuzhiyun SetAttrLgcyRetry:
5938*4882a593Smuzhiyun rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5939*4882a593Smuzhiyun (void **) &pSMBr);
5940*4882a593Smuzhiyun if (rc)
5941*4882a593Smuzhiyun return rc;
5942*4882a593Smuzhiyun
5943*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5944*4882a593Smuzhiyun name_len =
5945*4882a593Smuzhiyun ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5946*4882a593Smuzhiyun PATH_MAX, nls_codepage);
5947*4882a593Smuzhiyun name_len++; /* trailing null */
5948*4882a593Smuzhiyun name_len *= 2;
5949*4882a593Smuzhiyun } else {
5950*4882a593Smuzhiyun name_len = copy_path_name(pSMB->fileName, fileName);
5951*4882a593Smuzhiyun }
5952*4882a593Smuzhiyun pSMB->attr = cpu_to_le16(dos_attrs);
5953*4882a593Smuzhiyun pSMB->BufferFormat = 0x04;
5954*4882a593Smuzhiyun inc_rfc1001_len(pSMB, name_len + 1);
5955*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(name_len + 1);
5956*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5957*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5958*4882a593Smuzhiyun if (rc)
5959*4882a593Smuzhiyun cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
5960*4882a593Smuzhiyun
5961*4882a593Smuzhiyun cifs_buf_release(pSMB);
5962*4882a593Smuzhiyun
5963*4882a593Smuzhiyun if (rc == -EAGAIN)
5964*4882a593Smuzhiyun goto SetAttrLgcyRetry;
5965*4882a593Smuzhiyun
5966*4882a593Smuzhiyun return rc;
5967*4882a593Smuzhiyun }
5968*4882a593Smuzhiyun #endif /* temporarily unneeded SetAttr legacy function */
5969*4882a593Smuzhiyun
5970*4882a593Smuzhiyun static void
cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO * data_offset,const struct cifs_unix_set_info_args * args)5971*4882a593Smuzhiyun cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5972*4882a593Smuzhiyun const struct cifs_unix_set_info_args *args)
5973*4882a593Smuzhiyun {
5974*4882a593Smuzhiyun u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
5975*4882a593Smuzhiyun u64 mode = args->mode;
5976*4882a593Smuzhiyun
5977*4882a593Smuzhiyun if (uid_valid(args->uid))
5978*4882a593Smuzhiyun uid = from_kuid(&init_user_ns, args->uid);
5979*4882a593Smuzhiyun if (gid_valid(args->gid))
5980*4882a593Smuzhiyun gid = from_kgid(&init_user_ns, args->gid);
5981*4882a593Smuzhiyun
5982*4882a593Smuzhiyun /*
5983*4882a593Smuzhiyun * Samba server ignores set of file size to zero due to bugs in some
5984*4882a593Smuzhiyun * older clients, but we should be precise - we use SetFileSize to
5985*4882a593Smuzhiyun * set file size and do not want to truncate file size to zero
5986*4882a593Smuzhiyun * accidentally as happened on one Samba server beta by putting
5987*4882a593Smuzhiyun * zero instead of -1 here
5988*4882a593Smuzhiyun */
5989*4882a593Smuzhiyun data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5990*4882a593Smuzhiyun data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5991*4882a593Smuzhiyun data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5992*4882a593Smuzhiyun data_offset->LastAccessTime = cpu_to_le64(args->atime);
5993*4882a593Smuzhiyun data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5994*4882a593Smuzhiyun data_offset->Uid = cpu_to_le64(uid);
5995*4882a593Smuzhiyun data_offset->Gid = cpu_to_le64(gid);
5996*4882a593Smuzhiyun /* better to leave device as zero when it is */
5997*4882a593Smuzhiyun data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5998*4882a593Smuzhiyun data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5999*4882a593Smuzhiyun data_offset->Permissions = cpu_to_le64(mode);
6000*4882a593Smuzhiyun
6001*4882a593Smuzhiyun if (S_ISREG(mode))
6002*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_FILE);
6003*4882a593Smuzhiyun else if (S_ISDIR(mode))
6004*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_DIR);
6005*4882a593Smuzhiyun else if (S_ISLNK(mode))
6006*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
6007*4882a593Smuzhiyun else if (S_ISCHR(mode))
6008*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
6009*4882a593Smuzhiyun else if (S_ISBLK(mode))
6010*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
6011*4882a593Smuzhiyun else if (S_ISFIFO(mode))
6012*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_FIFO);
6013*4882a593Smuzhiyun else if (S_ISSOCK(mode))
6014*4882a593Smuzhiyun data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6015*4882a593Smuzhiyun }
6016*4882a593Smuzhiyun
6017*4882a593Smuzhiyun int
CIFSSMBUnixSetFileInfo(const unsigned int xid,struct cifs_tcon * tcon,const struct cifs_unix_set_info_args * args,u16 fid,u32 pid_of_opener)6018*4882a593Smuzhiyun CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
6019*4882a593Smuzhiyun const struct cifs_unix_set_info_args *args,
6020*4882a593Smuzhiyun u16 fid, u32 pid_of_opener)
6021*4882a593Smuzhiyun {
6022*4882a593Smuzhiyun struct smb_com_transaction2_sfi_req *pSMB = NULL;
6023*4882a593Smuzhiyun char *data_offset;
6024*4882a593Smuzhiyun int rc = 0;
6025*4882a593Smuzhiyun u16 params, param_offset, offset, byte_count, count;
6026*4882a593Smuzhiyun
6027*4882a593Smuzhiyun cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
6028*4882a593Smuzhiyun rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6029*4882a593Smuzhiyun
6030*4882a593Smuzhiyun if (rc)
6031*4882a593Smuzhiyun return rc;
6032*4882a593Smuzhiyun
6033*4882a593Smuzhiyun pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6034*4882a593Smuzhiyun pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6035*4882a593Smuzhiyun
6036*4882a593Smuzhiyun params = 6;
6037*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
6038*4882a593Smuzhiyun pSMB->Reserved = 0;
6039*4882a593Smuzhiyun pSMB->Flags = 0;
6040*4882a593Smuzhiyun pSMB->Timeout = 0;
6041*4882a593Smuzhiyun pSMB->Reserved2 = 0;
6042*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6043*4882a593Smuzhiyun offset = param_offset + params;
6044*4882a593Smuzhiyun
6045*4882a593Smuzhiyun data_offset = (char *)pSMB +
6046*4882a593Smuzhiyun offsetof(struct smb_hdr, Protocol) + offset;
6047*4882a593Smuzhiyun
6048*4882a593Smuzhiyun count = sizeof(FILE_UNIX_BASIC_INFO);
6049*4882a593Smuzhiyun
6050*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
6051*4882a593Smuzhiyun /* BB find max SMB PDU from sess */
6052*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
6053*4882a593Smuzhiyun pSMB->SetupCount = 1;
6054*4882a593Smuzhiyun pSMB->Reserved3 = 0;
6055*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6056*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
6057*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
6058*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
6059*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
6060*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
6061*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
6062*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
6063*4882a593Smuzhiyun pSMB->Fid = fid;
6064*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6065*4882a593Smuzhiyun pSMB->Reserved4 = 0;
6066*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
6067*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
6068*4882a593Smuzhiyun
6069*4882a593Smuzhiyun cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
6070*4882a593Smuzhiyun
6071*4882a593Smuzhiyun rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6072*4882a593Smuzhiyun cifs_small_buf_release(pSMB);
6073*4882a593Smuzhiyun if (rc)
6074*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6075*4882a593Smuzhiyun rc);
6076*4882a593Smuzhiyun
6077*4882a593Smuzhiyun /* Note: On -EAGAIN error only caller can retry on handle based calls
6078*4882a593Smuzhiyun since file handle passed in no longer valid */
6079*4882a593Smuzhiyun
6080*4882a593Smuzhiyun return rc;
6081*4882a593Smuzhiyun }
6082*4882a593Smuzhiyun
6083*4882a593Smuzhiyun int
CIFSSMBUnixSetPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * file_name,const struct cifs_unix_set_info_args * args,const struct nls_table * nls_codepage,int remap)6084*4882a593Smuzhiyun CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
6085*4882a593Smuzhiyun const char *file_name,
6086*4882a593Smuzhiyun const struct cifs_unix_set_info_args *args,
6087*4882a593Smuzhiyun const struct nls_table *nls_codepage, int remap)
6088*4882a593Smuzhiyun {
6089*4882a593Smuzhiyun TRANSACTION2_SPI_REQ *pSMB = NULL;
6090*4882a593Smuzhiyun TRANSACTION2_SPI_RSP *pSMBr = NULL;
6091*4882a593Smuzhiyun int name_len;
6092*4882a593Smuzhiyun int rc = 0;
6093*4882a593Smuzhiyun int bytes_returned = 0;
6094*4882a593Smuzhiyun FILE_UNIX_BASIC_INFO *data_offset;
6095*4882a593Smuzhiyun __u16 params, param_offset, offset, count, byte_count;
6096*4882a593Smuzhiyun
6097*4882a593Smuzhiyun cifs_dbg(FYI, "In SetUID/GID/Mode\n");
6098*4882a593Smuzhiyun setPermsRetry:
6099*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6100*4882a593Smuzhiyun (void **) &pSMBr);
6101*4882a593Smuzhiyun if (rc)
6102*4882a593Smuzhiyun return rc;
6103*4882a593Smuzhiyun
6104*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6105*4882a593Smuzhiyun name_len =
6106*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
6107*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
6108*4882a593Smuzhiyun name_len++; /* trailing null */
6109*4882a593Smuzhiyun name_len *= 2;
6110*4882a593Smuzhiyun } else {
6111*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, file_name);
6112*4882a593Smuzhiyun }
6113*4882a593Smuzhiyun
6114*4882a593Smuzhiyun params = 6 + name_len;
6115*4882a593Smuzhiyun count = sizeof(FILE_UNIX_BASIC_INFO);
6116*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
6117*4882a593Smuzhiyun /* BB find max SMB PDU from sess structure BB */
6118*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
6119*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
6120*4882a593Smuzhiyun pSMB->Reserved = 0;
6121*4882a593Smuzhiyun pSMB->Flags = 0;
6122*4882a593Smuzhiyun pSMB->Timeout = 0;
6123*4882a593Smuzhiyun pSMB->Reserved2 = 0;
6124*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
6125*4882a593Smuzhiyun InformationLevel) - 4;
6126*4882a593Smuzhiyun offset = param_offset + params;
6127*4882a593Smuzhiyun data_offset =
6128*4882a593Smuzhiyun (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6129*4882a593Smuzhiyun offset);
6130*4882a593Smuzhiyun memset(data_offset, 0, count);
6131*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
6132*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
6133*4882a593Smuzhiyun pSMB->SetupCount = 1;
6134*4882a593Smuzhiyun pSMB->Reserved3 = 0;
6135*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6136*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
6137*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
6138*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
6139*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
6140*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
6141*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6142*4882a593Smuzhiyun pSMB->Reserved4 = 0;
6143*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
6144*4882a593Smuzhiyun
6145*4882a593Smuzhiyun cifs_fill_unix_set_info(data_offset, args);
6146*4882a593Smuzhiyun
6147*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
6148*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6149*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6150*4882a593Smuzhiyun if (rc)
6151*4882a593Smuzhiyun cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
6152*4882a593Smuzhiyun
6153*4882a593Smuzhiyun cifs_buf_release(pSMB);
6154*4882a593Smuzhiyun if (rc == -EAGAIN)
6155*4882a593Smuzhiyun goto setPermsRetry;
6156*4882a593Smuzhiyun return rc;
6157*4882a593Smuzhiyun }
6158*4882a593Smuzhiyun
6159*4882a593Smuzhiyun #ifdef CONFIG_CIFS_XATTR
6160*4882a593Smuzhiyun /*
6161*4882a593Smuzhiyun * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6162*4882a593Smuzhiyun * function used by listxattr and getxattr type calls. When ea_name is set,
6163*4882a593Smuzhiyun * it looks for that attribute name and stuffs that value into the EAData
6164*4882a593Smuzhiyun * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6165*4882a593Smuzhiyun * buffer. In both cases, the return value is either the length of the
6166*4882a593Smuzhiyun * resulting data or a negative error code. If EAData is a NULL pointer then
6167*4882a593Smuzhiyun * the data isn't copied to it, but the length is returned.
6168*4882a593Smuzhiyun */
6169*4882a593Smuzhiyun ssize_t
CIFSSMBQAllEAs(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,const unsigned char * ea_name,char * EAData,size_t buf_size,struct cifs_sb_info * cifs_sb)6170*4882a593Smuzhiyun CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
6171*4882a593Smuzhiyun const unsigned char *searchName, const unsigned char *ea_name,
6172*4882a593Smuzhiyun char *EAData, size_t buf_size,
6173*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
6174*4882a593Smuzhiyun {
6175*4882a593Smuzhiyun /* BB assumes one setup word */
6176*4882a593Smuzhiyun TRANSACTION2_QPI_REQ *pSMB = NULL;
6177*4882a593Smuzhiyun TRANSACTION2_QPI_RSP *pSMBr = NULL;
6178*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
6179*4882a593Smuzhiyun struct nls_table *nls_codepage = cifs_sb->local_nls;
6180*4882a593Smuzhiyun int rc = 0;
6181*4882a593Smuzhiyun int bytes_returned;
6182*4882a593Smuzhiyun int list_len;
6183*4882a593Smuzhiyun struct fealist *ea_response_data;
6184*4882a593Smuzhiyun struct fea *temp_fea;
6185*4882a593Smuzhiyun char *temp_ptr;
6186*4882a593Smuzhiyun char *end_of_smb;
6187*4882a593Smuzhiyun __u16 params, byte_count, data_offset;
6188*4882a593Smuzhiyun unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
6189*4882a593Smuzhiyun
6190*4882a593Smuzhiyun cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
6191*4882a593Smuzhiyun QAllEAsRetry:
6192*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6193*4882a593Smuzhiyun (void **) &pSMBr);
6194*4882a593Smuzhiyun if (rc)
6195*4882a593Smuzhiyun return rc;
6196*4882a593Smuzhiyun
6197*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6198*4882a593Smuzhiyun list_len =
6199*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6200*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
6201*4882a593Smuzhiyun list_len++; /* trailing null */
6202*4882a593Smuzhiyun list_len *= 2;
6203*4882a593Smuzhiyun } else {
6204*4882a593Smuzhiyun list_len = copy_path_name(pSMB->FileName, searchName);
6205*4882a593Smuzhiyun }
6206*4882a593Smuzhiyun
6207*4882a593Smuzhiyun params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
6208*4882a593Smuzhiyun pSMB->TotalDataCount = 0;
6209*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
6210*4882a593Smuzhiyun /* BB find exact max SMB PDU from sess structure BB */
6211*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
6212*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
6213*4882a593Smuzhiyun pSMB->Reserved = 0;
6214*4882a593Smuzhiyun pSMB->Flags = 0;
6215*4882a593Smuzhiyun pSMB->Timeout = 0;
6216*4882a593Smuzhiyun pSMB->Reserved2 = 0;
6217*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(offsetof(
6218*4882a593Smuzhiyun struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
6219*4882a593Smuzhiyun pSMB->DataCount = 0;
6220*4882a593Smuzhiyun pSMB->DataOffset = 0;
6221*4882a593Smuzhiyun pSMB->SetupCount = 1;
6222*4882a593Smuzhiyun pSMB->Reserved3 = 0;
6223*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6224*4882a593Smuzhiyun byte_count = params + 1 /* pad */ ;
6225*4882a593Smuzhiyun pSMB->TotalParameterCount = cpu_to_le16(params);
6226*4882a593Smuzhiyun pSMB->ParameterCount = pSMB->TotalParameterCount;
6227*4882a593Smuzhiyun pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6228*4882a593Smuzhiyun pSMB->Reserved4 = 0;
6229*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
6230*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
6231*4882a593Smuzhiyun
6232*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6233*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6234*4882a593Smuzhiyun if (rc) {
6235*4882a593Smuzhiyun cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
6236*4882a593Smuzhiyun goto QAllEAsOut;
6237*4882a593Smuzhiyun }
6238*4882a593Smuzhiyun
6239*4882a593Smuzhiyun
6240*4882a593Smuzhiyun /* BB also check enough total bytes returned */
6241*4882a593Smuzhiyun /* BB we need to improve the validity checking
6242*4882a593Smuzhiyun of these trans2 responses */
6243*4882a593Smuzhiyun
6244*4882a593Smuzhiyun rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6245*4882a593Smuzhiyun if (rc || get_bcc(&pSMBr->hdr) < 4) {
6246*4882a593Smuzhiyun rc = -EIO; /* bad smb */
6247*4882a593Smuzhiyun goto QAllEAsOut;
6248*4882a593Smuzhiyun }
6249*4882a593Smuzhiyun
6250*4882a593Smuzhiyun /* check that length of list is not more than bcc */
6251*4882a593Smuzhiyun /* check that each entry does not go beyond length
6252*4882a593Smuzhiyun of list */
6253*4882a593Smuzhiyun /* check that each element of each entry does not
6254*4882a593Smuzhiyun go beyond end of list */
6255*4882a593Smuzhiyun /* validate_trans2_offsets() */
6256*4882a593Smuzhiyun /* BB check if start of smb + data_offset > &bcc+ bcc */
6257*4882a593Smuzhiyun
6258*4882a593Smuzhiyun data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6259*4882a593Smuzhiyun ea_response_data = (struct fealist *)
6260*4882a593Smuzhiyun (((char *) &pSMBr->hdr.Protocol) + data_offset);
6261*4882a593Smuzhiyun
6262*4882a593Smuzhiyun list_len = le32_to_cpu(ea_response_data->list_len);
6263*4882a593Smuzhiyun cifs_dbg(FYI, "ea length %d\n", list_len);
6264*4882a593Smuzhiyun if (list_len <= 8) {
6265*4882a593Smuzhiyun cifs_dbg(FYI, "empty EA list returned from server\n");
6266*4882a593Smuzhiyun /* didn't find the named attribute */
6267*4882a593Smuzhiyun if (ea_name)
6268*4882a593Smuzhiyun rc = -ENODATA;
6269*4882a593Smuzhiyun goto QAllEAsOut;
6270*4882a593Smuzhiyun }
6271*4882a593Smuzhiyun
6272*4882a593Smuzhiyun /* make sure list_len doesn't go past end of SMB */
6273*4882a593Smuzhiyun end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6274*4882a593Smuzhiyun if ((char *)ea_response_data + list_len > end_of_smb) {
6275*4882a593Smuzhiyun cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
6276*4882a593Smuzhiyun rc = -EIO;
6277*4882a593Smuzhiyun goto QAllEAsOut;
6278*4882a593Smuzhiyun }
6279*4882a593Smuzhiyun
6280*4882a593Smuzhiyun /* account for ea list len */
6281*4882a593Smuzhiyun list_len -= 4;
6282*4882a593Smuzhiyun temp_fea = ea_response_data->list;
6283*4882a593Smuzhiyun temp_ptr = (char *)temp_fea;
6284*4882a593Smuzhiyun while (list_len > 0) {
6285*4882a593Smuzhiyun unsigned int name_len;
6286*4882a593Smuzhiyun __u16 value_len;
6287*4882a593Smuzhiyun
6288*4882a593Smuzhiyun list_len -= 4;
6289*4882a593Smuzhiyun temp_ptr += 4;
6290*4882a593Smuzhiyun /* make sure we can read name_len and value_len */
6291*4882a593Smuzhiyun if (list_len < 0) {
6292*4882a593Smuzhiyun cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6293*4882a593Smuzhiyun rc = -EIO;
6294*4882a593Smuzhiyun goto QAllEAsOut;
6295*4882a593Smuzhiyun }
6296*4882a593Smuzhiyun
6297*4882a593Smuzhiyun name_len = temp_fea->name_len;
6298*4882a593Smuzhiyun value_len = le16_to_cpu(temp_fea->value_len);
6299*4882a593Smuzhiyun list_len -= name_len + 1 + value_len;
6300*4882a593Smuzhiyun if (list_len < 0) {
6301*4882a593Smuzhiyun cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6302*4882a593Smuzhiyun rc = -EIO;
6303*4882a593Smuzhiyun goto QAllEAsOut;
6304*4882a593Smuzhiyun }
6305*4882a593Smuzhiyun
6306*4882a593Smuzhiyun if (ea_name) {
6307*4882a593Smuzhiyun if (ea_name_len == name_len &&
6308*4882a593Smuzhiyun memcmp(ea_name, temp_ptr, name_len) == 0) {
6309*4882a593Smuzhiyun temp_ptr += name_len + 1;
6310*4882a593Smuzhiyun rc = value_len;
6311*4882a593Smuzhiyun if (buf_size == 0)
6312*4882a593Smuzhiyun goto QAllEAsOut;
6313*4882a593Smuzhiyun if ((size_t)value_len > buf_size) {
6314*4882a593Smuzhiyun rc = -ERANGE;
6315*4882a593Smuzhiyun goto QAllEAsOut;
6316*4882a593Smuzhiyun }
6317*4882a593Smuzhiyun memcpy(EAData, temp_ptr, value_len);
6318*4882a593Smuzhiyun goto QAllEAsOut;
6319*4882a593Smuzhiyun }
6320*4882a593Smuzhiyun } else {
6321*4882a593Smuzhiyun /* account for prefix user. and trailing null */
6322*4882a593Smuzhiyun rc += (5 + 1 + name_len);
6323*4882a593Smuzhiyun if (rc < (int) buf_size) {
6324*4882a593Smuzhiyun memcpy(EAData, "user.", 5);
6325*4882a593Smuzhiyun EAData += 5;
6326*4882a593Smuzhiyun memcpy(EAData, temp_ptr, name_len);
6327*4882a593Smuzhiyun EAData += name_len;
6328*4882a593Smuzhiyun /* null terminate name */
6329*4882a593Smuzhiyun *EAData = 0;
6330*4882a593Smuzhiyun ++EAData;
6331*4882a593Smuzhiyun } else if (buf_size == 0) {
6332*4882a593Smuzhiyun /* skip copy - calc size only */
6333*4882a593Smuzhiyun } else {
6334*4882a593Smuzhiyun /* stop before overrun buffer */
6335*4882a593Smuzhiyun rc = -ERANGE;
6336*4882a593Smuzhiyun break;
6337*4882a593Smuzhiyun }
6338*4882a593Smuzhiyun }
6339*4882a593Smuzhiyun temp_ptr += name_len + 1 + value_len;
6340*4882a593Smuzhiyun temp_fea = (struct fea *)temp_ptr;
6341*4882a593Smuzhiyun }
6342*4882a593Smuzhiyun
6343*4882a593Smuzhiyun /* didn't find the named attribute */
6344*4882a593Smuzhiyun if (ea_name)
6345*4882a593Smuzhiyun rc = -ENODATA;
6346*4882a593Smuzhiyun
6347*4882a593Smuzhiyun QAllEAsOut:
6348*4882a593Smuzhiyun cifs_buf_release(pSMB);
6349*4882a593Smuzhiyun if (rc == -EAGAIN)
6350*4882a593Smuzhiyun goto QAllEAsRetry;
6351*4882a593Smuzhiyun
6352*4882a593Smuzhiyun return (ssize_t)rc;
6353*4882a593Smuzhiyun }
6354*4882a593Smuzhiyun
6355*4882a593Smuzhiyun int
CIFSSMBSetEA(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const char * ea_name,const void * ea_value,const __u16 ea_value_len,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)6356*4882a593Smuzhiyun CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6357*4882a593Smuzhiyun const char *fileName, const char *ea_name, const void *ea_value,
6358*4882a593Smuzhiyun const __u16 ea_value_len, const struct nls_table *nls_codepage,
6359*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
6360*4882a593Smuzhiyun {
6361*4882a593Smuzhiyun struct smb_com_transaction2_spi_req *pSMB = NULL;
6362*4882a593Smuzhiyun struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6363*4882a593Smuzhiyun struct fealist *parm_data;
6364*4882a593Smuzhiyun int name_len;
6365*4882a593Smuzhiyun int rc = 0;
6366*4882a593Smuzhiyun int bytes_returned = 0;
6367*4882a593Smuzhiyun __u16 params, param_offset, byte_count, offset, count;
6368*4882a593Smuzhiyun int remap = cifs_remap(cifs_sb);
6369*4882a593Smuzhiyun
6370*4882a593Smuzhiyun cifs_dbg(FYI, "In SetEA\n");
6371*4882a593Smuzhiyun SetEARetry:
6372*4882a593Smuzhiyun rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6373*4882a593Smuzhiyun (void **) &pSMBr);
6374*4882a593Smuzhiyun if (rc)
6375*4882a593Smuzhiyun return rc;
6376*4882a593Smuzhiyun
6377*4882a593Smuzhiyun if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6378*4882a593Smuzhiyun name_len =
6379*4882a593Smuzhiyun cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6380*4882a593Smuzhiyun PATH_MAX, nls_codepage, remap);
6381*4882a593Smuzhiyun name_len++; /* trailing null */
6382*4882a593Smuzhiyun name_len *= 2;
6383*4882a593Smuzhiyun } else {
6384*4882a593Smuzhiyun name_len = copy_path_name(pSMB->FileName, fileName);
6385*4882a593Smuzhiyun }
6386*4882a593Smuzhiyun
6387*4882a593Smuzhiyun params = 6 + name_len;
6388*4882a593Smuzhiyun
6389*4882a593Smuzhiyun /* done calculating parms using name_len of file name,
6390*4882a593Smuzhiyun now use name_len to calculate length of ea name
6391*4882a593Smuzhiyun we are going to create in the inode xattrs */
6392*4882a593Smuzhiyun if (ea_name == NULL)
6393*4882a593Smuzhiyun name_len = 0;
6394*4882a593Smuzhiyun else
6395*4882a593Smuzhiyun name_len = strnlen(ea_name, 255);
6396*4882a593Smuzhiyun
6397*4882a593Smuzhiyun count = sizeof(*parm_data) + ea_value_len + name_len;
6398*4882a593Smuzhiyun pSMB->MaxParameterCount = cpu_to_le16(2);
6399*4882a593Smuzhiyun /* BB find max SMB PDU from sess */
6400*4882a593Smuzhiyun pSMB->MaxDataCount = cpu_to_le16(1000);
6401*4882a593Smuzhiyun pSMB->MaxSetupCount = 0;
6402*4882a593Smuzhiyun pSMB->Reserved = 0;
6403*4882a593Smuzhiyun pSMB->Flags = 0;
6404*4882a593Smuzhiyun pSMB->Timeout = 0;
6405*4882a593Smuzhiyun pSMB->Reserved2 = 0;
6406*4882a593Smuzhiyun param_offset = offsetof(struct smb_com_transaction2_spi_req,
6407*4882a593Smuzhiyun InformationLevel) - 4;
6408*4882a593Smuzhiyun offset = param_offset + params;
6409*4882a593Smuzhiyun pSMB->InformationLevel =
6410*4882a593Smuzhiyun cpu_to_le16(SMB_SET_FILE_EA);
6411*4882a593Smuzhiyun
6412*4882a593Smuzhiyun parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
6413*4882a593Smuzhiyun pSMB->ParameterOffset = cpu_to_le16(param_offset);
6414*4882a593Smuzhiyun pSMB->DataOffset = cpu_to_le16(offset);
6415*4882a593Smuzhiyun pSMB->SetupCount = 1;
6416*4882a593Smuzhiyun pSMB->Reserved3 = 0;
6417*4882a593Smuzhiyun pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6418*4882a593Smuzhiyun byte_count = 3 /* pad */ + params + count;
6419*4882a593Smuzhiyun pSMB->DataCount = cpu_to_le16(count);
6420*4882a593Smuzhiyun parm_data->list_len = cpu_to_le32(count);
6421*4882a593Smuzhiyun parm_data->list[0].EA_flags = 0;
6422*4882a593Smuzhiyun /* we checked above that name len is less than 255 */
6423*4882a593Smuzhiyun parm_data->list[0].name_len = (__u8)name_len;
6424*4882a593Smuzhiyun /* EA names are always ASCII */
6425*4882a593Smuzhiyun if (ea_name)
6426*4882a593Smuzhiyun strncpy(parm_data->list[0].name, ea_name, name_len);
6427*4882a593Smuzhiyun parm_data->list[0].name[name_len] = 0;
6428*4882a593Smuzhiyun parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6429*4882a593Smuzhiyun /* caller ensures that ea_value_len is less than 64K but
6430*4882a593Smuzhiyun we need to ensure that it fits within the smb */
6431*4882a593Smuzhiyun
6432*4882a593Smuzhiyun /*BB add length check to see if it would fit in
6433*4882a593Smuzhiyun negotiated SMB buffer size BB */
6434*4882a593Smuzhiyun /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6435*4882a593Smuzhiyun if (ea_value_len)
6436*4882a593Smuzhiyun memcpy(parm_data->list[0].name+name_len+1,
6437*4882a593Smuzhiyun ea_value, ea_value_len);
6438*4882a593Smuzhiyun
6439*4882a593Smuzhiyun pSMB->TotalDataCount = pSMB->DataCount;
6440*4882a593Smuzhiyun pSMB->ParameterCount = cpu_to_le16(params);
6441*4882a593Smuzhiyun pSMB->TotalParameterCount = pSMB->ParameterCount;
6442*4882a593Smuzhiyun pSMB->Reserved4 = 0;
6443*4882a593Smuzhiyun inc_rfc1001_len(pSMB, byte_count);
6444*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(byte_count);
6445*4882a593Smuzhiyun rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6446*4882a593Smuzhiyun (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6447*4882a593Smuzhiyun if (rc)
6448*4882a593Smuzhiyun cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
6449*4882a593Smuzhiyun
6450*4882a593Smuzhiyun cifs_buf_release(pSMB);
6451*4882a593Smuzhiyun
6452*4882a593Smuzhiyun if (rc == -EAGAIN)
6453*4882a593Smuzhiyun goto SetEARetry;
6454*4882a593Smuzhiyun
6455*4882a593Smuzhiyun return rc;
6456*4882a593Smuzhiyun }
6457*4882a593Smuzhiyun #endif
6458