xref: /OK3568_Linux_fs/kernel/fs/cifs/smb1ops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  SMB1 (CIFS) version specific operations
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/pagemap.h>
9*4882a593Smuzhiyun #include <linux/vfs.h>
10*4882a593Smuzhiyun #include "cifsglob.h"
11*4882a593Smuzhiyun #include "cifsproto.h"
12*4882a593Smuzhiyun #include "cifs_debug.h"
13*4882a593Smuzhiyun #include "cifspdu.h"
14*4882a593Smuzhiyun #include "cifs_unicode.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun  * An NT cancel request header looks just like the original request except:
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * The Command is SMB_COM_NT_CANCEL
20*4882a593Smuzhiyun  * The WordCount is zeroed out
21*4882a593Smuzhiyun  * The ByteCount is zeroed out
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * This function mangles an existing request buffer into a
24*4882a593Smuzhiyun  * SMB_COM_NT_CANCEL request and then sends it.
25*4882a593Smuzhiyun  */
26*4882a593Smuzhiyun static int
send_nt_cancel(struct TCP_Server_Info * server,struct smb_rqst * rqst,struct mid_q_entry * mid)27*4882a593Smuzhiyun send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
28*4882a593Smuzhiyun 	       struct mid_q_entry *mid)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun 	int rc = 0;
31*4882a593Smuzhiyun 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	/* -4 for RFC1001 length and +2 for BCC field */
34*4882a593Smuzhiyun 	in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
35*4882a593Smuzhiyun 	in_buf->Command = SMB_COM_NT_CANCEL;
36*4882a593Smuzhiyun 	in_buf->WordCount = 0;
37*4882a593Smuzhiyun 	put_bcc(0, in_buf);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	mutex_lock(&server->srv_mutex);
40*4882a593Smuzhiyun 	rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
41*4882a593Smuzhiyun 	if (rc) {
42*4882a593Smuzhiyun 		mutex_unlock(&server->srv_mutex);
43*4882a593Smuzhiyun 		return rc;
44*4882a593Smuzhiyun 	}
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/*
47*4882a593Smuzhiyun 	 * The response to this call was already factored into the sequence
48*4882a593Smuzhiyun 	 * number when the call went out, so we must adjust it back downward
49*4882a593Smuzhiyun 	 * after signing here.
50*4882a593Smuzhiyun 	 */
51*4882a593Smuzhiyun 	--server->sequence_number;
52*4882a593Smuzhiyun 	rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
53*4882a593Smuzhiyun 	if (rc < 0)
54*4882a593Smuzhiyun 		server->sequence_number--;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	mutex_unlock(&server->srv_mutex);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
59*4882a593Smuzhiyun 		 get_mid(in_buf), rc);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	return rc;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static bool
cifs_compare_fids(struct cifsFileInfo * ob1,struct cifsFileInfo * ob2)65*4882a593Smuzhiyun cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	return ob1->fid.netfid == ob2->fid.netfid;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun static unsigned int
cifs_read_data_offset(char * buf)71*4882a593Smuzhiyun cifs_read_data_offset(char *buf)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	READ_RSP *rsp = (READ_RSP *)buf;
74*4882a593Smuzhiyun 	return le16_to_cpu(rsp->DataOffset);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static unsigned int
cifs_read_data_length(char * buf,bool in_remaining)78*4882a593Smuzhiyun cifs_read_data_length(char *buf, bool in_remaining)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	READ_RSP *rsp = (READ_RSP *)buf;
81*4882a593Smuzhiyun 	/* It's a bug reading remaining data for SMB1 packets */
82*4882a593Smuzhiyun 	WARN_ON(in_remaining);
83*4882a593Smuzhiyun 	return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
84*4882a593Smuzhiyun 	       le16_to_cpu(rsp->DataLength);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static struct mid_q_entry *
cifs_find_mid(struct TCP_Server_Info * server,char * buffer)88*4882a593Smuzhiyun cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	struct smb_hdr *buf = (struct smb_hdr *)buffer;
91*4882a593Smuzhiyun 	struct mid_q_entry *mid;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	spin_lock(&GlobalMid_Lock);
94*4882a593Smuzhiyun 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
95*4882a593Smuzhiyun 		if (compare_mid(mid->mid, buf) &&
96*4882a593Smuzhiyun 		    mid->mid_state == MID_REQUEST_SUBMITTED &&
97*4882a593Smuzhiyun 		    le16_to_cpu(mid->command) == buf->Command) {
98*4882a593Smuzhiyun 			kref_get(&mid->refcount);
99*4882a593Smuzhiyun 			spin_unlock(&GlobalMid_Lock);
100*4882a593Smuzhiyun 			return mid;
101*4882a593Smuzhiyun 		}
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 	spin_unlock(&GlobalMid_Lock);
104*4882a593Smuzhiyun 	return NULL;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static void
cifs_add_credits(struct TCP_Server_Info * server,const struct cifs_credits * credits,const int optype)108*4882a593Smuzhiyun cifs_add_credits(struct TCP_Server_Info *server,
109*4882a593Smuzhiyun 		 const struct cifs_credits *credits, const int optype)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	spin_lock(&server->req_lock);
112*4882a593Smuzhiyun 	server->credits += credits->value;
113*4882a593Smuzhiyun 	server->in_flight--;
114*4882a593Smuzhiyun 	spin_unlock(&server->req_lock);
115*4882a593Smuzhiyun 	wake_up(&server->request_q);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static void
cifs_set_credits(struct TCP_Server_Info * server,const int val)119*4882a593Smuzhiyun cifs_set_credits(struct TCP_Server_Info *server, const int val)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	spin_lock(&server->req_lock);
122*4882a593Smuzhiyun 	server->credits = val;
123*4882a593Smuzhiyun 	server->oplocks = val > 1 ? enable_oplocks : false;
124*4882a593Smuzhiyun 	spin_unlock(&server->req_lock);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun static int *
cifs_get_credits_field(struct TCP_Server_Info * server,const int optype)128*4882a593Smuzhiyun cifs_get_credits_field(struct TCP_Server_Info *server, const int optype)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	return &server->credits;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun static unsigned int
cifs_get_credits(struct mid_q_entry * mid)134*4882a593Smuzhiyun cifs_get_credits(struct mid_q_entry *mid)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	return 1;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /*
140*4882a593Smuzhiyun  * Find a free multiplex id (SMB mid). Otherwise there could be
141*4882a593Smuzhiyun  * mid collisions which might cause problems, demultiplexing the
142*4882a593Smuzhiyun  * wrong response to this request. Multiplex ids could collide if
143*4882a593Smuzhiyun  * one of a series requests takes much longer than the others, or
144*4882a593Smuzhiyun  * if a very large number of long lived requests (byte range
145*4882a593Smuzhiyun  * locks or FindNotify requests) are pending. No more than
146*4882a593Smuzhiyun  * 64K-1 requests can be outstanding at one time. If no
147*4882a593Smuzhiyun  * mids are available, return zero. A future optimization
148*4882a593Smuzhiyun  * could make the combination of mids and uid the key we use
149*4882a593Smuzhiyun  * to demultiplex on (rather than mid alone).
150*4882a593Smuzhiyun  * In addition to the above check, the cifs demultiplex
151*4882a593Smuzhiyun  * code already used the command code as a secondary
152*4882a593Smuzhiyun  * check of the frame and if signing is negotiated the
153*4882a593Smuzhiyun  * response would be discarded if the mid were the same
154*4882a593Smuzhiyun  * but the signature was wrong. Since the mid is not put in the
155*4882a593Smuzhiyun  * pending queue until later (when it is about to be dispatched)
156*4882a593Smuzhiyun  * we do have to limit the number of outstanding requests
157*4882a593Smuzhiyun  * to somewhat less than 64K-1 although it is hard to imagine
158*4882a593Smuzhiyun  * so many threads being in the vfs at one time.
159*4882a593Smuzhiyun  */
160*4882a593Smuzhiyun static __u64
cifs_get_next_mid(struct TCP_Server_Info * server)161*4882a593Smuzhiyun cifs_get_next_mid(struct TCP_Server_Info *server)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	__u64 mid = 0;
164*4882a593Smuzhiyun 	__u16 last_mid, cur_mid;
165*4882a593Smuzhiyun 	bool collision;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	spin_lock(&GlobalMid_Lock);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* mid is 16 bit only for CIFS/SMB */
170*4882a593Smuzhiyun 	cur_mid = (__u16)((server->CurrentMid) & 0xffff);
171*4882a593Smuzhiyun 	/* we do not want to loop forever */
172*4882a593Smuzhiyun 	last_mid = cur_mid;
173*4882a593Smuzhiyun 	cur_mid++;
174*4882a593Smuzhiyun 	/* avoid 0xFFFF MID */
175*4882a593Smuzhiyun 	if (cur_mid == 0xffff)
176*4882a593Smuzhiyun 		cur_mid++;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/*
179*4882a593Smuzhiyun 	 * This nested loop looks more expensive than it is.
180*4882a593Smuzhiyun 	 * In practice the list of pending requests is short,
181*4882a593Smuzhiyun 	 * fewer than 50, and the mids are likely to be unique
182*4882a593Smuzhiyun 	 * on the first pass through the loop unless some request
183*4882a593Smuzhiyun 	 * takes longer than the 64 thousand requests before it
184*4882a593Smuzhiyun 	 * (and it would also have to have been a request that
185*4882a593Smuzhiyun 	 * did not time out).
186*4882a593Smuzhiyun 	 */
187*4882a593Smuzhiyun 	while (cur_mid != last_mid) {
188*4882a593Smuzhiyun 		struct mid_q_entry *mid_entry;
189*4882a593Smuzhiyun 		unsigned int num_mids;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		collision = false;
192*4882a593Smuzhiyun 		if (cur_mid == 0)
193*4882a593Smuzhiyun 			cur_mid++;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		num_mids = 0;
196*4882a593Smuzhiyun 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
197*4882a593Smuzhiyun 			++num_mids;
198*4882a593Smuzhiyun 			if (mid_entry->mid == cur_mid &&
199*4882a593Smuzhiyun 			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
200*4882a593Smuzhiyun 				/* This mid is in use, try a different one */
201*4882a593Smuzhiyun 				collision = true;
202*4882a593Smuzhiyun 				break;
203*4882a593Smuzhiyun 			}
204*4882a593Smuzhiyun 		}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 		/*
207*4882a593Smuzhiyun 		 * if we have more than 32k mids in the list, then something
208*4882a593Smuzhiyun 		 * is very wrong. Possibly a local user is trying to DoS the
209*4882a593Smuzhiyun 		 * box by issuing long-running calls and SIGKILL'ing them. If
210*4882a593Smuzhiyun 		 * we get to 2^16 mids then we're in big trouble as this
211*4882a593Smuzhiyun 		 * function could loop forever.
212*4882a593Smuzhiyun 		 *
213*4882a593Smuzhiyun 		 * Go ahead and assign out the mid in this situation, but force
214*4882a593Smuzhiyun 		 * an eventual reconnect to clean out the pending_mid_q.
215*4882a593Smuzhiyun 		 */
216*4882a593Smuzhiyun 		if (num_mids > 32768)
217*4882a593Smuzhiyun 			server->tcpStatus = CifsNeedReconnect;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		if (!collision) {
220*4882a593Smuzhiyun 			mid = (__u64)cur_mid;
221*4882a593Smuzhiyun 			server->CurrentMid = mid;
222*4882a593Smuzhiyun 			break;
223*4882a593Smuzhiyun 		}
224*4882a593Smuzhiyun 		cur_mid++;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 	spin_unlock(&GlobalMid_Lock);
227*4882a593Smuzhiyun 	return mid;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun /*
231*4882a593Smuzhiyun 	return codes:
232*4882a593Smuzhiyun 		0	not a transact2, or all data present
233*4882a593Smuzhiyun 		>0	transact2 with that much data missing
234*4882a593Smuzhiyun 		-EINVAL	invalid transact2
235*4882a593Smuzhiyun  */
236*4882a593Smuzhiyun static int
check2ndT2(char * buf)237*4882a593Smuzhiyun check2ndT2(char *buf)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
240*4882a593Smuzhiyun 	struct smb_t2_rsp *pSMBt;
241*4882a593Smuzhiyun 	int remaining;
242*4882a593Smuzhiyun 	__u16 total_data_size, data_in_this_rsp;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (pSMB->Command != SMB_COM_TRANSACTION2)
245*4882a593Smuzhiyun 		return 0;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* check for plausible wct, bcc and t2 data and parm sizes */
248*4882a593Smuzhiyun 	/* check for parm and data offset going beyond end of smb */
249*4882a593Smuzhiyun 	if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
250*4882a593Smuzhiyun 		cifs_dbg(FYI, "Invalid transact2 word count\n");
251*4882a593Smuzhiyun 		return -EINVAL;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	pSMBt = (struct smb_t2_rsp *)pSMB;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
257*4882a593Smuzhiyun 	data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (total_data_size == data_in_this_rsp)
260*4882a593Smuzhiyun 		return 0;
261*4882a593Smuzhiyun 	else if (total_data_size < data_in_this_rsp) {
262*4882a593Smuzhiyun 		cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
263*4882a593Smuzhiyun 			 total_data_size, data_in_this_rsp);
264*4882a593Smuzhiyun 		return -EINVAL;
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	remaining = total_data_size - data_in_this_rsp;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
270*4882a593Smuzhiyun 		 remaining);
271*4882a593Smuzhiyun 	if (total_data_size > CIFSMaxBufSize) {
272*4882a593Smuzhiyun 		cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
273*4882a593Smuzhiyun 			 total_data_size, CIFSMaxBufSize);
274*4882a593Smuzhiyun 		return -EINVAL;
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 	return remaining;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun static int
coalesce_t2(char * second_buf,struct smb_hdr * target_hdr)280*4882a593Smuzhiyun coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
283*4882a593Smuzhiyun 	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
284*4882a593Smuzhiyun 	char *data_area_of_tgt;
285*4882a593Smuzhiyun 	char *data_area_of_src;
286*4882a593Smuzhiyun 	int remaining;
287*4882a593Smuzhiyun 	unsigned int byte_count, total_in_tgt;
288*4882a593Smuzhiyun 	__u16 tgt_total_cnt, src_total_cnt, total_in_src;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
291*4882a593Smuzhiyun 	tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	if (tgt_total_cnt != src_total_cnt)
294*4882a593Smuzhiyun 		cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
295*4882a593Smuzhiyun 			 src_total_cnt, tgt_total_cnt);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	remaining = tgt_total_cnt - total_in_tgt;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (remaining < 0) {
302*4882a593Smuzhiyun 		cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
303*4882a593Smuzhiyun 			 tgt_total_cnt, total_in_tgt);
304*4882a593Smuzhiyun 		return -EPROTO;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (remaining == 0) {
308*4882a593Smuzhiyun 		/* nothing to do, ignore */
309*4882a593Smuzhiyun 		cifs_dbg(FYI, "no more data remains\n");
310*4882a593Smuzhiyun 		return 0;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
314*4882a593Smuzhiyun 	if (remaining < total_in_src)
315*4882a593Smuzhiyun 		cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	/* find end of first SMB data area */
318*4882a593Smuzhiyun 	data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
319*4882a593Smuzhiyun 				get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/* validate target area */
322*4882a593Smuzhiyun 	data_area_of_src = (char *)&pSMBs->hdr.Protocol +
323*4882a593Smuzhiyun 				get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	data_area_of_tgt += total_in_tgt;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	total_in_tgt += total_in_src;
328*4882a593Smuzhiyun 	/* is the result too big for the field? */
329*4882a593Smuzhiyun 	if (total_in_tgt > USHRT_MAX) {
330*4882a593Smuzhiyun 		cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
331*4882a593Smuzhiyun 			 total_in_tgt);
332*4882a593Smuzhiyun 		return -EPROTO;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* fix up the BCC */
337*4882a593Smuzhiyun 	byte_count = get_bcc(target_hdr);
338*4882a593Smuzhiyun 	byte_count += total_in_src;
339*4882a593Smuzhiyun 	/* is the result too big for the field? */
340*4882a593Smuzhiyun 	if (byte_count > USHRT_MAX) {
341*4882a593Smuzhiyun 		cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
342*4882a593Smuzhiyun 		return -EPROTO;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	put_bcc(byte_count, target_hdr);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
347*4882a593Smuzhiyun 	byte_count += total_in_src;
348*4882a593Smuzhiyun 	/* don't allow buffer to overflow */
349*4882a593Smuzhiyun 	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
350*4882a593Smuzhiyun 		cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
351*4882a593Smuzhiyun 			 byte_count);
352*4882a593Smuzhiyun 		return -ENOBUFS;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/* copy second buffer into end of first buffer */
357*4882a593Smuzhiyun 	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (remaining != total_in_src) {
360*4882a593Smuzhiyun 		/* more responses to go */
361*4882a593Smuzhiyun 		cifs_dbg(FYI, "waiting for more secondary responses\n");
362*4882a593Smuzhiyun 		return 1;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/* we are done */
366*4882a593Smuzhiyun 	cifs_dbg(FYI, "found the last secondary response\n");
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static void
cifs_downgrade_oplock(struct TCP_Server_Info * server,struct cifsInodeInfo * cinode,__u32 oplock,unsigned int epoch,bool * purge_cache)371*4882a593Smuzhiyun cifs_downgrade_oplock(struct TCP_Server_Info *server,
372*4882a593Smuzhiyun 		      struct cifsInodeInfo *cinode, __u32 oplock,
373*4882a593Smuzhiyun 		      unsigned int epoch, bool *purge_cache)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	cifs_set_oplock_level(cinode, oplock);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun static bool
cifs_check_trans2(struct mid_q_entry * mid,struct TCP_Server_Info * server,char * buf,int malformed)379*4882a593Smuzhiyun cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
380*4882a593Smuzhiyun 		  char *buf, int malformed)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	if (malformed)
383*4882a593Smuzhiyun 		return false;
384*4882a593Smuzhiyun 	if (check2ndT2(buf) <= 0)
385*4882a593Smuzhiyun 		return false;
386*4882a593Smuzhiyun 	mid->multiRsp = true;
387*4882a593Smuzhiyun 	if (mid->resp_buf) {
388*4882a593Smuzhiyun 		/* merge response - fix up 1st*/
389*4882a593Smuzhiyun 		malformed = coalesce_t2(buf, mid->resp_buf);
390*4882a593Smuzhiyun 		if (malformed > 0)
391*4882a593Smuzhiyun 			return true;
392*4882a593Smuzhiyun 		/* All parts received or packet is malformed. */
393*4882a593Smuzhiyun 		mid->multiEnd = true;
394*4882a593Smuzhiyun 		dequeue_mid(mid, malformed);
395*4882a593Smuzhiyun 		return true;
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 	if (!server->large_buf) {
398*4882a593Smuzhiyun 		/*FIXME: switch to already allocated largebuf?*/
399*4882a593Smuzhiyun 		cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
400*4882a593Smuzhiyun 	} else {
401*4882a593Smuzhiyun 		/* Have first buffer */
402*4882a593Smuzhiyun 		mid->resp_buf = buf;
403*4882a593Smuzhiyun 		mid->large_buf = true;
404*4882a593Smuzhiyun 		server->bigbuf = NULL;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 	return true;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun static bool
cifs_need_neg(struct TCP_Server_Info * server)410*4882a593Smuzhiyun cifs_need_neg(struct TCP_Server_Info *server)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	return server->maxBuf == 0;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun static int
cifs_negotiate(const unsigned int xid,struct cifs_ses * ses)416*4882a593Smuzhiyun cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	int rc;
419*4882a593Smuzhiyun 	rc = CIFSSMBNegotiate(xid, ses);
420*4882a593Smuzhiyun 	if (rc == -EAGAIN) {
421*4882a593Smuzhiyun 		/* retry only once on 1st time connection */
422*4882a593Smuzhiyun 		set_credits(ses->server, 1);
423*4882a593Smuzhiyun 		rc = CIFSSMBNegotiate(xid, ses);
424*4882a593Smuzhiyun 		if (rc == -EAGAIN)
425*4882a593Smuzhiyun 			rc = -EHOSTDOWN;
426*4882a593Smuzhiyun 	}
427*4882a593Smuzhiyun 	return rc;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun static unsigned int
cifs_negotiate_wsize(struct cifs_tcon * tcon,struct smb_vol * volume_info)431*4882a593Smuzhiyun cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
434*4882a593Smuzhiyun 	struct TCP_Server_Info *server = tcon->ses->server;
435*4882a593Smuzhiyun 	unsigned int wsize;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	/* start with specified wsize, or default */
438*4882a593Smuzhiyun 	if (volume_info->wsize)
439*4882a593Smuzhiyun 		wsize = volume_info->wsize;
440*4882a593Smuzhiyun 	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
441*4882a593Smuzhiyun 		wsize = CIFS_DEFAULT_IOSIZE;
442*4882a593Smuzhiyun 	else
443*4882a593Smuzhiyun 		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* can server support 24-bit write sizes? (via UNIX extensions) */
446*4882a593Smuzhiyun 	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
447*4882a593Smuzhiyun 		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	/*
450*4882a593Smuzhiyun 	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
451*4882a593Smuzhiyun 	 * Limit it to max buffer offered by the server, minus the size of the
452*4882a593Smuzhiyun 	 * WRITEX header, not including the 4 byte RFC1001 length.
453*4882a593Smuzhiyun 	 */
454*4882a593Smuzhiyun 	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
455*4882a593Smuzhiyun 	    (!(server->capabilities & CAP_UNIX) && server->sign))
456*4882a593Smuzhiyun 		wsize = min_t(unsigned int, wsize,
457*4882a593Smuzhiyun 				server->maxBuf - sizeof(WRITE_REQ) + 4);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	/* hard limit of CIFS_MAX_WSIZE */
460*4882a593Smuzhiyun 	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return wsize;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun static unsigned int
cifs_negotiate_rsize(struct cifs_tcon * tcon,struct smb_vol * volume_info)466*4882a593Smuzhiyun cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
469*4882a593Smuzhiyun 	struct TCP_Server_Info *server = tcon->ses->server;
470*4882a593Smuzhiyun 	unsigned int rsize, defsize;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	/*
473*4882a593Smuzhiyun 	 * Set default value...
474*4882a593Smuzhiyun 	 *
475*4882a593Smuzhiyun 	 * HACK alert! Ancient servers have very small buffers. Even though
476*4882a593Smuzhiyun 	 * MS-CIFS indicates that servers are only limited by the client's
477*4882a593Smuzhiyun 	 * bufsize for reads, testing against win98se shows that it throws
478*4882a593Smuzhiyun 	 * INVALID_PARAMETER errors if you try to request too large a read.
479*4882a593Smuzhiyun 	 * OS/2 just sends back short reads.
480*4882a593Smuzhiyun 	 *
481*4882a593Smuzhiyun 	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
482*4882a593Smuzhiyun 	 * it can't handle a read request larger than its MaxBufferSize either.
483*4882a593Smuzhiyun 	 */
484*4882a593Smuzhiyun 	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
485*4882a593Smuzhiyun 		defsize = CIFS_DEFAULT_IOSIZE;
486*4882a593Smuzhiyun 	else if (server->capabilities & CAP_LARGE_READ_X)
487*4882a593Smuzhiyun 		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
488*4882a593Smuzhiyun 	else
489*4882a593Smuzhiyun 		defsize = server->maxBuf - sizeof(READ_RSP);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	rsize = volume_info->rsize ? volume_info->rsize : defsize;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	/*
494*4882a593Smuzhiyun 	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
495*4882a593Smuzhiyun 	 * the client's MaxBufferSize.
496*4882a593Smuzhiyun 	 */
497*4882a593Smuzhiyun 	if (!(server->capabilities & CAP_LARGE_READ_X))
498*4882a593Smuzhiyun 		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	/* hard limit of CIFS_MAX_RSIZE */
501*4882a593Smuzhiyun 	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	return rsize;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun static void
cifs_qfs_tcon(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb)507*4882a593Smuzhiyun cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
508*4882a593Smuzhiyun 	      struct cifs_sb_info *cifs_sb)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	CIFSSMBQFSDeviceInfo(xid, tcon);
511*4882a593Smuzhiyun 	CIFSSMBQFSAttributeInfo(xid, tcon);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun static int
cifs_is_path_accessible(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path)515*4882a593Smuzhiyun cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
516*4882a593Smuzhiyun 			struct cifs_sb_info *cifs_sb, const char *full_path)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	int rc;
519*4882a593Smuzhiyun 	FILE_ALL_INFO *file_info;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	file_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
522*4882a593Smuzhiyun 	if (file_info == NULL)
523*4882a593Smuzhiyun 		return -ENOMEM;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
526*4882a593Smuzhiyun 			      0 /* not legacy */, cifs_sb->local_nls,
527*4882a593Smuzhiyun 			      cifs_remap(cifs_sb));
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (rc == -EOPNOTSUPP || rc == -EINVAL)
530*4882a593Smuzhiyun 		rc = SMBQueryInformation(xid, tcon, full_path, file_info,
531*4882a593Smuzhiyun 				cifs_sb->local_nls, cifs_remap(cifs_sb));
532*4882a593Smuzhiyun 	kfree(file_info);
533*4882a593Smuzhiyun 	return rc;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun static int
cifs_query_path_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,FILE_ALL_INFO * data,bool * adjustTZ,bool * symlink)537*4882a593Smuzhiyun cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
538*4882a593Smuzhiyun 		     struct cifs_sb_info *cifs_sb, const char *full_path,
539*4882a593Smuzhiyun 		     FILE_ALL_INFO *data, bool *adjustTZ, bool *symlink)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	int rc;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	*symlink = false;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/* could do find first instead but this returns more info */
546*4882a593Smuzhiyun 	rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */,
547*4882a593Smuzhiyun 			      cifs_sb->local_nls, cifs_remap(cifs_sb));
548*4882a593Smuzhiyun 	/*
549*4882a593Smuzhiyun 	 * BB optimize code so we do not make the above call when server claims
550*4882a593Smuzhiyun 	 * no NT SMB support and the above call failed at least once - set flag
551*4882a593Smuzhiyun 	 * in tcon or mount.
552*4882a593Smuzhiyun 	 */
553*4882a593Smuzhiyun 	if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
554*4882a593Smuzhiyun 		rc = SMBQueryInformation(xid, tcon, full_path, data,
555*4882a593Smuzhiyun 					 cifs_sb->local_nls,
556*4882a593Smuzhiyun 					 cifs_remap(cifs_sb));
557*4882a593Smuzhiyun 		*adjustTZ = true;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (!rc && (le32_to_cpu(data->Attributes) & ATTR_REPARSE)) {
561*4882a593Smuzhiyun 		int tmprc;
562*4882a593Smuzhiyun 		int oplock = 0;
563*4882a593Smuzhiyun 		struct cifs_fid fid;
564*4882a593Smuzhiyun 		struct cifs_open_parms oparms;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 		oparms.tcon = tcon;
567*4882a593Smuzhiyun 		oparms.cifs_sb = cifs_sb;
568*4882a593Smuzhiyun 		oparms.desired_access = FILE_READ_ATTRIBUTES;
569*4882a593Smuzhiyun 		oparms.create_options = cifs_create_options(cifs_sb, 0);
570*4882a593Smuzhiyun 		oparms.disposition = FILE_OPEN;
571*4882a593Smuzhiyun 		oparms.path = full_path;
572*4882a593Smuzhiyun 		oparms.fid = &fid;
573*4882a593Smuzhiyun 		oparms.reconnect = false;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 		/* Need to check if this is a symbolic link or not */
576*4882a593Smuzhiyun 		tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
577*4882a593Smuzhiyun 		if (tmprc == -EOPNOTSUPP)
578*4882a593Smuzhiyun 			*symlink = true;
579*4882a593Smuzhiyun 		else if (tmprc == 0)
580*4882a593Smuzhiyun 			CIFSSMBClose(xid, tcon, fid.netfid);
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	return rc;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun static int
cifs_get_srv_inum(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,u64 * uniqueid,FILE_ALL_INFO * data)587*4882a593Smuzhiyun cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
588*4882a593Smuzhiyun 		  struct cifs_sb_info *cifs_sb, const char *full_path,
589*4882a593Smuzhiyun 		  u64 *uniqueid, FILE_ALL_INFO *data)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	/*
592*4882a593Smuzhiyun 	 * We can not use the IndexNumber field by default from Windows or
593*4882a593Smuzhiyun 	 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
594*4882a593Smuzhiyun 	 * CIFS spec claims that this value is unique within the scope of a
595*4882a593Smuzhiyun 	 * share, and the windows docs hint that it's actually unique
596*4882a593Smuzhiyun 	 * per-machine.
597*4882a593Smuzhiyun 	 *
598*4882a593Smuzhiyun 	 * There may be higher info levels that work but are there Windows
599*4882a593Smuzhiyun 	 * server or network appliances for which IndexNumber field is not
600*4882a593Smuzhiyun 	 * guaranteed unique?
601*4882a593Smuzhiyun 	 */
602*4882a593Smuzhiyun 	return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid,
603*4882a593Smuzhiyun 				     cifs_sb->local_nls,
604*4882a593Smuzhiyun 				     cifs_remap(cifs_sb));
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun static int
cifs_query_file_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid,FILE_ALL_INFO * data)608*4882a593Smuzhiyun cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
609*4882a593Smuzhiyun 		     struct cifs_fid *fid, FILE_ALL_INFO *data)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun static void
cifs_clear_stats(struct cifs_tcon * tcon)615*4882a593Smuzhiyun cifs_clear_stats(struct cifs_tcon *tcon)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
618*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
619*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
620*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
621*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
622*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
623*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
624*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
625*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
626*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
627*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
628*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
629*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
630*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
631*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
632*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
633*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
634*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
635*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
636*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
637*4882a593Smuzhiyun 	atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun static void
cifs_print_stats(struct seq_file * m,struct cifs_tcon * tcon)641*4882a593Smuzhiyun cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	seq_printf(m, " Oplocks breaks: %d",
644*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
645*4882a593Smuzhiyun 	seq_printf(m, "\nReads:  %d Bytes: %llu",
646*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_reads),
647*4882a593Smuzhiyun 		   (long long)(tcon->bytes_read));
648*4882a593Smuzhiyun 	seq_printf(m, "\nWrites: %d Bytes: %llu",
649*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_writes),
650*4882a593Smuzhiyun 		   (long long)(tcon->bytes_written));
651*4882a593Smuzhiyun 	seq_printf(m, "\nFlushes: %d",
652*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_flushes));
653*4882a593Smuzhiyun 	seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
654*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_locks),
655*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
656*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_symlinks));
657*4882a593Smuzhiyun 	seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
658*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_opens),
659*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_closes),
660*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_deletes));
661*4882a593Smuzhiyun 	seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
662*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_posixopens),
663*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
664*4882a593Smuzhiyun 	seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
665*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
666*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
667*4882a593Smuzhiyun 	seq_printf(m, "\nRenames: %d T2 Renames %d",
668*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_renames),
669*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_t2renames));
670*4882a593Smuzhiyun 	seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
671*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_ffirst),
672*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_fnext),
673*4882a593Smuzhiyun 		   atomic_read(&tcon->stats.cifs_stats.num_fclose));
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun static void
cifs_mkdir_setinfo(struct inode * inode,const char * full_path,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)677*4882a593Smuzhiyun cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
678*4882a593Smuzhiyun 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
679*4882a593Smuzhiyun 		   const unsigned int xid)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun 	FILE_BASIC_INFO info;
682*4882a593Smuzhiyun 	struct cifsInodeInfo *cifsInode;
683*4882a593Smuzhiyun 	u32 dosattrs;
684*4882a593Smuzhiyun 	int rc;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	memset(&info, 0, sizeof(info));
687*4882a593Smuzhiyun 	cifsInode = CIFS_I(inode);
688*4882a593Smuzhiyun 	dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
689*4882a593Smuzhiyun 	info.Attributes = cpu_to_le32(dosattrs);
690*4882a593Smuzhiyun 	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
691*4882a593Smuzhiyun 				cifs_sb);
692*4882a593Smuzhiyun 	if (rc == 0)
693*4882a593Smuzhiyun 		cifsInode->cifsAttrs = dosattrs;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun static int
cifs_open_file(const unsigned int xid,struct cifs_open_parms * oparms,__u32 * oplock,FILE_ALL_INFO * buf)697*4882a593Smuzhiyun cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
698*4882a593Smuzhiyun 	       __u32 *oplock, FILE_ALL_INFO *buf)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
701*4882a593Smuzhiyun 		return SMBLegacyOpen(xid, oparms->tcon, oparms->path,
702*4882a593Smuzhiyun 				     oparms->disposition,
703*4882a593Smuzhiyun 				     oparms->desired_access,
704*4882a593Smuzhiyun 				     oparms->create_options,
705*4882a593Smuzhiyun 				     &oparms->fid->netfid, oplock, buf,
706*4882a593Smuzhiyun 				     oparms->cifs_sb->local_nls,
707*4882a593Smuzhiyun 				     cifs_remap(oparms->cifs_sb));
708*4882a593Smuzhiyun 	return CIFS_open(xid, oparms, oplock, buf);
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun static void
cifs_set_fid(struct cifsFileInfo * cfile,struct cifs_fid * fid,__u32 oplock)712*4882a593Smuzhiyun cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
715*4882a593Smuzhiyun 	cfile->fid.netfid = fid->netfid;
716*4882a593Smuzhiyun 	cifs_set_oplock_level(cinode, oplock);
717*4882a593Smuzhiyun 	cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static void
cifs_close_file(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)721*4882a593Smuzhiyun cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
722*4882a593Smuzhiyun 		struct cifs_fid *fid)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	CIFSSMBClose(xid, tcon, fid->netfid);
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun static int
cifs_flush_file(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)728*4882a593Smuzhiyun cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
729*4882a593Smuzhiyun 		struct cifs_fid *fid)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	return CIFSSMBFlush(xid, tcon, fid->netfid);
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun static int
cifs_sync_read(const unsigned int xid,struct cifs_fid * pfid,struct cifs_io_parms * parms,unsigned int * bytes_read,char ** buf,int * buf_type)735*4882a593Smuzhiyun cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid,
736*4882a593Smuzhiyun 	       struct cifs_io_parms *parms, unsigned int *bytes_read,
737*4882a593Smuzhiyun 	       char **buf, int *buf_type)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 	parms->netfid = pfid->netfid;
740*4882a593Smuzhiyun 	return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun static int
cifs_sync_write(const unsigned int xid,struct cifs_fid * pfid,struct cifs_io_parms * parms,unsigned int * written,struct kvec * iov,unsigned long nr_segs)744*4882a593Smuzhiyun cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid,
745*4882a593Smuzhiyun 		struct cifs_io_parms *parms, unsigned int *written,
746*4882a593Smuzhiyun 		struct kvec *iov, unsigned long nr_segs)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	parms->netfid = pfid->netfid;
750*4882a593Smuzhiyun 	return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun static int
smb_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)754*4882a593Smuzhiyun smb_set_file_info(struct inode *inode, const char *full_path,
755*4882a593Smuzhiyun 		  FILE_BASIC_INFO *buf, const unsigned int xid)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun 	int oplock = 0;
758*4882a593Smuzhiyun 	int rc;
759*4882a593Smuzhiyun 	__u32 netpid;
760*4882a593Smuzhiyun 	struct cifs_fid fid;
761*4882a593Smuzhiyun 	struct cifs_open_parms oparms;
762*4882a593Smuzhiyun 	struct cifsFileInfo *open_file;
763*4882a593Smuzhiyun 	struct cifsInodeInfo *cinode = CIFS_I(inode);
764*4882a593Smuzhiyun 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
765*4882a593Smuzhiyun 	struct tcon_link *tlink = NULL;
766*4882a593Smuzhiyun 	struct cifs_tcon *tcon;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	/* if the file is already open for write, just use that fileid */
769*4882a593Smuzhiyun 	open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
770*4882a593Smuzhiyun 	if (open_file) {
771*4882a593Smuzhiyun 		fid.netfid = open_file->fid.netfid;
772*4882a593Smuzhiyun 		netpid = open_file->pid;
773*4882a593Smuzhiyun 		tcon = tlink_tcon(open_file->tlink);
774*4882a593Smuzhiyun 		goto set_via_filehandle;
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	tlink = cifs_sb_tlink(cifs_sb);
778*4882a593Smuzhiyun 	if (IS_ERR(tlink)) {
779*4882a593Smuzhiyun 		rc = PTR_ERR(tlink);
780*4882a593Smuzhiyun 		tlink = NULL;
781*4882a593Smuzhiyun 		goto out;
782*4882a593Smuzhiyun 	}
783*4882a593Smuzhiyun 	tcon = tlink_tcon(tlink);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
786*4882a593Smuzhiyun 				cifs_sb);
787*4882a593Smuzhiyun 	if (rc == 0) {
788*4882a593Smuzhiyun 		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
789*4882a593Smuzhiyun 		goto out;
790*4882a593Smuzhiyun 	} else if (rc != -EOPNOTSUPP && rc != -EINVAL) {
791*4882a593Smuzhiyun 		goto out;
792*4882a593Smuzhiyun 	}
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	oparms.tcon = tcon;
795*4882a593Smuzhiyun 	oparms.cifs_sb = cifs_sb;
796*4882a593Smuzhiyun 	oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
797*4882a593Smuzhiyun 	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
798*4882a593Smuzhiyun 	oparms.disposition = FILE_OPEN;
799*4882a593Smuzhiyun 	oparms.path = full_path;
800*4882a593Smuzhiyun 	oparms.fid = &fid;
801*4882a593Smuzhiyun 	oparms.reconnect = false;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
804*4882a593Smuzhiyun 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
805*4882a593Smuzhiyun 	if (rc != 0) {
806*4882a593Smuzhiyun 		if (rc == -EIO)
807*4882a593Smuzhiyun 			rc = -EINVAL;
808*4882a593Smuzhiyun 		goto out;
809*4882a593Smuzhiyun 	}
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	netpid = current->tgid;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun set_via_filehandle:
814*4882a593Smuzhiyun 	rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
815*4882a593Smuzhiyun 	if (!rc)
816*4882a593Smuzhiyun 		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	if (open_file == NULL)
819*4882a593Smuzhiyun 		CIFSSMBClose(xid, tcon, fid.netfid);
820*4882a593Smuzhiyun 	else
821*4882a593Smuzhiyun 		cifsFileInfo_put(open_file);
822*4882a593Smuzhiyun out:
823*4882a593Smuzhiyun 	if (tlink != NULL)
824*4882a593Smuzhiyun 		cifs_put_tlink(tlink);
825*4882a593Smuzhiyun 	return rc;
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun static int
cifs_set_compression(const unsigned int xid,struct cifs_tcon * tcon,struct cifsFileInfo * cfile)829*4882a593Smuzhiyun cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
830*4882a593Smuzhiyun 		   struct cifsFileInfo *cfile)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun 	return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun static int
cifs_query_dir_first(const unsigned int xid,struct cifs_tcon * tcon,const char * path,struct cifs_sb_info * cifs_sb,struct cifs_fid * fid,__u16 search_flags,struct cifs_search_info * srch_inf)836*4882a593Smuzhiyun cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
837*4882a593Smuzhiyun 		     const char *path, struct cifs_sb_info *cifs_sb,
838*4882a593Smuzhiyun 		     struct cifs_fid *fid, __u16 search_flags,
839*4882a593Smuzhiyun 		     struct cifs_search_info *srch_inf)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun 	int rc;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	rc = CIFSFindFirst(xid, tcon, path, cifs_sb,
844*4882a593Smuzhiyun 			   &fid->netfid, search_flags, srch_inf, true);
845*4882a593Smuzhiyun 	if (rc)
846*4882a593Smuzhiyun 		cifs_dbg(FYI, "find first failed=%d\n", rc);
847*4882a593Smuzhiyun 	return rc;
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun static int
cifs_query_dir_next(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid,__u16 search_flags,struct cifs_search_info * srch_inf)851*4882a593Smuzhiyun cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
852*4882a593Smuzhiyun 		    struct cifs_fid *fid, __u16 search_flags,
853*4882a593Smuzhiyun 		    struct cifs_search_info *srch_inf)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun 	return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun static int
cifs_close_dir(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)859*4882a593Smuzhiyun cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
860*4882a593Smuzhiyun 	       struct cifs_fid *fid)
861*4882a593Smuzhiyun {
862*4882a593Smuzhiyun 	return CIFSFindClose(xid, tcon, fid->netfid);
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun static int
cifs_oplock_response(struct cifs_tcon * tcon,struct cifs_fid * fid,struct cifsInodeInfo * cinode)866*4882a593Smuzhiyun cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
867*4882a593Smuzhiyun 		     struct cifsInodeInfo *cinode)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun 	return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
870*4882a593Smuzhiyun 			   LOCKING_ANDX_OPLOCK_RELEASE, false,
871*4882a593Smuzhiyun 			   CIFS_CACHE_READ(cinode) ? 1 : 0);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun static int
cifs_queryfs(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,struct kstatfs * buf)875*4882a593Smuzhiyun cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
876*4882a593Smuzhiyun 	     struct cifs_sb_info *cifs_sb, struct kstatfs *buf)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun 	int rc = -EOPNOTSUPP;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	buf->f_type = CIFS_MAGIC_NUMBER;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	/*
883*4882a593Smuzhiyun 	 * We could add a second check for a QFS Unix capability bit
884*4882a593Smuzhiyun 	 */
885*4882a593Smuzhiyun 	if ((tcon->ses->capabilities & CAP_UNIX) &&
886*4882a593Smuzhiyun 	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
887*4882a593Smuzhiyun 		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/*
890*4882a593Smuzhiyun 	 * Only need to call the old QFSInfo if failed on newer one,
891*4882a593Smuzhiyun 	 * e.g. by OS/2.
892*4882a593Smuzhiyun 	 **/
893*4882a593Smuzhiyun 	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
894*4882a593Smuzhiyun 		rc = CIFSSMBQFSInfo(xid, tcon, buf);
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	/*
897*4882a593Smuzhiyun 	 * Some old Windows servers also do not support level 103, retry with
898*4882a593Smuzhiyun 	 * older level one if old server failed the previous call or we
899*4882a593Smuzhiyun 	 * bypassed it because we detected that this was an older LANMAN sess
900*4882a593Smuzhiyun 	 */
901*4882a593Smuzhiyun 	if (rc)
902*4882a593Smuzhiyun 		rc = SMBOldQFSInfo(xid, tcon, buf);
903*4882a593Smuzhiyun 	return rc;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun static int
cifs_mand_lock(const unsigned int xid,struct cifsFileInfo * cfile,__u64 offset,__u64 length,__u32 type,int lock,int unlock,bool wait)907*4882a593Smuzhiyun cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
908*4882a593Smuzhiyun 	       __u64 length, __u32 type, int lock, int unlock, bool wait)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun 	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
911*4882a593Smuzhiyun 			   current->tgid, length, offset, unlock, lock,
912*4882a593Smuzhiyun 			   (__u8)type, wait, 0);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun static int
cifs_unix_dfs_readlink(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,char ** symlinkinfo,const struct nls_table * nls_codepage)916*4882a593Smuzhiyun cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
917*4882a593Smuzhiyun 		       const unsigned char *searchName, char **symlinkinfo,
918*4882a593Smuzhiyun 		       const struct nls_table *nls_codepage)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
921*4882a593Smuzhiyun 	int rc;
922*4882a593Smuzhiyun 	struct dfs_info3_param referral = {0};
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral,
925*4882a593Smuzhiyun 			  0);
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	if (!rc) {
928*4882a593Smuzhiyun 		*symlinkinfo = kstrndup(referral.node_name,
929*4882a593Smuzhiyun 					strlen(referral.node_name),
930*4882a593Smuzhiyun 					GFP_KERNEL);
931*4882a593Smuzhiyun 		free_dfs_info_param(&referral);
932*4882a593Smuzhiyun 		if (!*symlinkinfo)
933*4882a593Smuzhiyun 			rc = -ENOMEM;
934*4882a593Smuzhiyun 	}
935*4882a593Smuzhiyun 	return rc;
936*4882a593Smuzhiyun #else /* No DFS support */
937*4882a593Smuzhiyun 	return -EREMOTE;
938*4882a593Smuzhiyun #endif
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun static int
cifs_query_symlink(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,char ** target_path,bool is_reparse_point)942*4882a593Smuzhiyun cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
943*4882a593Smuzhiyun 		   struct cifs_sb_info *cifs_sb, const char *full_path,
944*4882a593Smuzhiyun 		   char **target_path, bool is_reparse_point)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun 	int rc;
947*4882a593Smuzhiyun 	int oplock = 0;
948*4882a593Smuzhiyun 	struct cifs_fid fid;
949*4882a593Smuzhiyun 	struct cifs_open_parms oparms;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	if (is_reparse_point) {
954*4882a593Smuzhiyun 		cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n");
955*4882a593Smuzhiyun 		return -EOPNOTSUPP;
956*4882a593Smuzhiyun 	}
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	/* Check for unix extensions */
959*4882a593Smuzhiyun 	if (cap_unix(tcon->ses)) {
960*4882a593Smuzhiyun 		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
961*4882a593Smuzhiyun 					     cifs_sb->local_nls,
962*4882a593Smuzhiyun 					     cifs_remap(cifs_sb));
963*4882a593Smuzhiyun 		if (rc == -EREMOTE)
964*4882a593Smuzhiyun 			rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
965*4882a593Smuzhiyun 						    target_path,
966*4882a593Smuzhiyun 						    cifs_sb->local_nls);
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 		goto out;
969*4882a593Smuzhiyun 	}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	oparms.tcon = tcon;
972*4882a593Smuzhiyun 	oparms.cifs_sb = cifs_sb;
973*4882a593Smuzhiyun 	oparms.desired_access = FILE_READ_ATTRIBUTES;
974*4882a593Smuzhiyun 	oparms.create_options = cifs_create_options(cifs_sb,
975*4882a593Smuzhiyun 						    OPEN_REPARSE_POINT);
976*4882a593Smuzhiyun 	oparms.disposition = FILE_OPEN;
977*4882a593Smuzhiyun 	oparms.path = full_path;
978*4882a593Smuzhiyun 	oparms.fid = &fid;
979*4882a593Smuzhiyun 	oparms.reconnect = false;
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
982*4882a593Smuzhiyun 	if (rc)
983*4882a593Smuzhiyun 		goto out;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
986*4882a593Smuzhiyun 				 cifs_sb->local_nls);
987*4882a593Smuzhiyun 	if (rc)
988*4882a593Smuzhiyun 		goto out_close;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	convert_delimiter(*target_path, '/');
991*4882a593Smuzhiyun out_close:
992*4882a593Smuzhiyun 	CIFSSMBClose(xid, tcon, fid.netfid);
993*4882a593Smuzhiyun out:
994*4882a593Smuzhiyun 	if (!rc)
995*4882a593Smuzhiyun 		cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
996*4882a593Smuzhiyun 	return rc;
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun static bool
cifs_is_read_op(__u32 oplock)1000*4882a593Smuzhiyun cifs_is_read_op(__u32 oplock)
1001*4882a593Smuzhiyun {
1002*4882a593Smuzhiyun 	return oplock == OPLOCK_READ;
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun static unsigned int
cifs_wp_retry_size(struct inode * inode)1006*4882a593Smuzhiyun cifs_wp_retry_size(struct inode *inode)
1007*4882a593Smuzhiyun {
1008*4882a593Smuzhiyun 	return CIFS_SB(inode->i_sb)->wsize;
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun static bool
cifs_dir_needs_close(struct cifsFileInfo * cfile)1012*4882a593Smuzhiyun cifs_dir_needs_close(struct cifsFileInfo *cfile)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun 	return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun static bool
cifs_can_echo(struct TCP_Server_Info * server)1018*4882a593Smuzhiyun cifs_can_echo(struct TCP_Server_Info *server)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun 	if (server->tcpStatus == CifsGood)
1021*4882a593Smuzhiyun 		return true;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	return false;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun static int
cifs_make_node(unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,char * full_path,umode_t mode,dev_t dev)1027*4882a593Smuzhiyun cifs_make_node(unsigned int xid, struct inode *inode,
1028*4882a593Smuzhiyun 	       struct dentry *dentry, struct cifs_tcon *tcon,
1029*4882a593Smuzhiyun 	       char *full_path, umode_t mode, dev_t dev)
1030*4882a593Smuzhiyun {
1031*4882a593Smuzhiyun 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1032*4882a593Smuzhiyun 	struct inode *newinode = NULL;
1033*4882a593Smuzhiyun 	int rc = -EPERM;
1034*4882a593Smuzhiyun 	FILE_ALL_INFO *buf = NULL;
1035*4882a593Smuzhiyun 	struct cifs_io_parms io_parms;
1036*4882a593Smuzhiyun 	__u32 oplock = 0;
1037*4882a593Smuzhiyun 	struct cifs_fid fid;
1038*4882a593Smuzhiyun 	struct cifs_open_parms oparms;
1039*4882a593Smuzhiyun 	unsigned int bytes_written;
1040*4882a593Smuzhiyun 	struct win_dev *pdev;
1041*4882a593Smuzhiyun 	struct kvec iov[2];
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	if (tcon->unix_ext) {
1044*4882a593Smuzhiyun 		/*
1045*4882a593Smuzhiyun 		 * SMB1 Unix Extensions: requires server support but
1046*4882a593Smuzhiyun 		 * works with all special files
1047*4882a593Smuzhiyun 		 */
1048*4882a593Smuzhiyun 		struct cifs_unix_set_info_args args = {
1049*4882a593Smuzhiyun 			.mode	= mode & ~current_umask(),
1050*4882a593Smuzhiyun 			.ctime	= NO_CHANGE_64,
1051*4882a593Smuzhiyun 			.atime	= NO_CHANGE_64,
1052*4882a593Smuzhiyun 			.mtime	= NO_CHANGE_64,
1053*4882a593Smuzhiyun 			.device	= dev,
1054*4882a593Smuzhiyun 		};
1055*4882a593Smuzhiyun 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1056*4882a593Smuzhiyun 			args.uid = current_fsuid();
1057*4882a593Smuzhiyun 			args.gid = current_fsgid();
1058*4882a593Smuzhiyun 		} else {
1059*4882a593Smuzhiyun 			args.uid = INVALID_UID; /* no change */
1060*4882a593Smuzhiyun 			args.gid = INVALID_GID; /* no change */
1061*4882a593Smuzhiyun 		}
1062*4882a593Smuzhiyun 		rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
1063*4882a593Smuzhiyun 					    cifs_sb->local_nls,
1064*4882a593Smuzhiyun 					    cifs_remap(cifs_sb));
1065*4882a593Smuzhiyun 		if (rc)
1066*4882a593Smuzhiyun 			goto out;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 		rc = cifs_get_inode_info_unix(&newinode, full_path,
1069*4882a593Smuzhiyun 					      inode->i_sb, xid);
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 		if (rc == 0)
1072*4882a593Smuzhiyun 			d_instantiate(dentry, newinode);
1073*4882a593Smuzhiyun 		goto out;
1074*4882a593Smuzhiyun 	}
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	/*
1077*4882a593Smuzhiyun 	 * SMB1 SFU emulation: should work with all servers, but only
1078*4882a593Smuzhiyun 	 * support block and char device (no socket & fifo)
1079*4882a593Smuzhiyun 	 */
1080*4882a593Smuzhiyun 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
1081*4882a593Smuzhiyun 		goto out;
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (!S_ISCHR(mode) && !S_ISBLK(mode))
1084*4882a593Smuzhiyun 		goto out;
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	cifs_dbg(FYI, "sfu compat create special file\n");
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
1089*4882a593Smuzhiyun 	if (buf == NULL) {
1090*4882a593Smuzhiyun 		rc = -ENOMEM;
1091*4882a593Smuzhiyun 		goto out;
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	oparms.tcon = tcon;
1095*4882a593Smuzhiyun 	oparms.cifs_sb = cifs_sb;
1096*4882a593Smuzhiyun 	oparms.desired_access = GENERIC_WRITE;
1097*4882a593Smuzhiyun 	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
1098*4882a593Smuzhiyun 						    CREATE_OPTION_SPECIAL);
1099*4882a593Smuzhiyun 	oparms.disposition = FILE_CREATE;
1100*4882a593Smuzhiyun 	oparms.path = full_path;
1101*4882a593Smuzhiyun 	oparms.fid = &fid;
1102*4882a593Smuzhiyun 	oparms.reconnect = false;
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	if (tcon->ses->server->oplocks)
1105*4882a593Smuzhiyun 		oplock = REQ_OPLOCK;
1106*4882a593Smuzhiyun 	else
1107*4882a593Smuzhiyun 		oplock = 0;
1108*4882a593Smuzhiyun 	rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
1109*4882a593Smuzhiyun 	if (rc)
1110*4882a593Smuzhiyun 		goto out;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	/*
1113*4882a593Smuzhiyun 	 * BB Do not bother to decode buf since no local inode yet to put
1114*4882a593Smuzhiyun 	 * timestamps in, but we can reuse it safely.
1115*4882a593Smuzhiyun 	 */
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	pdev = (struct win_dev *)buf;
1118*4882a593Smuzhiyun 	io_parms.pid = current->tgid;
1119*4882a593Smuzhiyun 	io_parms.tcon = tcon;
1120*4882a593Smuzhiyun 	io_parms.offset = 0;
1121*4882a593Smuzhiyun 	io_parms.length = sizeof(struct win_dev);
1122*4882a593Smuzhiyun 	iov[1].iov_base = buf;
1123*4882a593Smuzhiyun 	iov[1].iov_len = sizeof(struct win_dev);
1124*4882a593Smuzhiyun 	if (S_ISCHR(mode)) {
1125*4882a593Smuzhiyun 		memcpy(pdev->type, "IntxCHR", 8);
1126*4882a593Smuzhiyun 		pdev->major = cpu_to_le64(MAJOR(dev));
1127*4882a593Smuzhiyun 		pdev->minor = cpu_to_le64(MINOR(dev));
1128*4882a593Smuzhiyun 		rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
1129*4882a593Smuzhiyun 							&bytes_written, iov, 1);
1130*4882a593Smuzhiyun 	} else if (S_ISBLK(mode)) {
1131*4882a593Smuzhiyun 		memcpy(pdev->type, "IntxBLK", 8);
1132*4882a593Smuzhiyun 		pdev->major = cpu_to_le64(MAJOR(dev));
1133*4882a593Smuzhiyun 		pdev->minor = cpu_to_le64(MINOR(dev));
1134*4882a593Smuzhiyun 		rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
1135*4882a593Smuzhiyun 							&bytes_written, iov, 1);
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun 	tcon->ses->server->ops->close(xid, tcon, &fid);
1138*4882a593Smuzhiyun 	d_drop(dentry);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	/* FIXME: add code here to set EAs */
1141*4882a593Smuzhiyun out:
1142*4882a593Smuzhiyun 	kfree(buf);
1143*4882a593Smuzhiyun 	return rc;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun struct smb_version_operations smb1_operations = {
1149*4882a593Smuzhiyun 	.send_cancel = send_nt_cancel,
1150*4882a593Smuzhiyun 	.compare_fids = cifs_compare_fids,
1151*4882a593Smuzhiyun 	.setup_request = cifs_setup_request,
1152*4882a593Smuzhiyun 	.setup_async_request = cifs_setup_async_request,
1153*4882a593Smuzhiyun 	.check_receive = cifs_check_receive,
1154*4882a593Smuzhiyun 	.add_credits = cifs_add_credits,
1155*4882a593Smuzhiyun 	.set_credits = cifs_set_credits,
1156*4882a593Smuzhiyun 	.get_credits_field = cifs_get_credits_field,
1157*4882a593Smuzhiyun 	.get_credits = cifs_get_credits,
1158*4882a593Smuzhiyun 	.wait_mtu_credits = cifs_wait_mtu_credits,
1159*4882a593Smuzhiyun 	.get_next_mid = cifs_get_next_mid,
1160*4882a593Smuzhiyun 	.read_data_offset = cifs_read_data_offset,
1161*4882a593Smuzhiyun 	.read_data_length = cifs_read_data_length,
1162*4882a593Smuzhiyun 	.map_error = map_smb_to_linux_error,
1163*4882a593Smuzhiyun 	.find_mid = cifs_find_mid,
1164*4882a593Smuzhiyun 	.check_message = checkSMB,
1165*4882a593Smuzhiyun 	.dump_detail = cifs_dump_detail,
1166*4882a593Smuzhiyun 	.clear_stats = cifs_clear_stats,
1167*4882a593Smuzhiyun 	.print_stats = cifs_print_stats,
1168*4882a593Smuzhiyun 	.is_oplock_break = is_valid_oplock_break,
1169*4882a593Smuzhiyun 	.downgrade_oplock = cifs_downgrade_oplock,
1170*4882a593Smuzhiyun 	.check_trans2 = cifs_check_trans2,
1171*4882a593Smuzhiyun 	.need_neg = cifs_need_neg,
1172*4882a593Smuzhiyun 	.negotiate = cifs_negotiate,
1173*4882a593Smuzhiyun 	.negotiate_wsize = cifs_negotiate_wsize,
1174*4882a593Smuzhiyun 	.negotiate_rsize = cifs_negotiate_rsize,
1175*4882a593Smuzhiyun 	.sess_setup = CIFS_SessSetup,
1176*4882a593Smuzhiyun 	.logoff = CIFSSMBLogoff,
1177*4882a593Smuzhiyun 	.tree_connect = CIFSTCon,
1178*4882a593Smuzhiyun 	.tree_disconnect = CIFSSMBTDis,
1179*4882a593Smuzhiyun 	.get_dfs_refer = CIFSGetDFSRefer,
1180*4882a593Smuzhiyun 	.qfs_tcon = cifs_qfs_tcon,
1181*4882a593Smuzhiyun 	.is_path_accessible = cifs_is_path_accessible,
1182*4882a593Smuzhiyun 	.can_echo = cifs_can_echo,
1183*4882a593Smuzhiyun 	.query_path_info = cifs_query_path_info,
1184*4882a593Smuzhiyun 	.query_file_info = cifs_query_file_info,
1185*4882a593Smuzhiyun 	.get_srv_inum = cifs_get_srv_inum,
1186*4882a593Smuzhiyun 	.set_path_size = CIFSSMBSetEOF,
1187*4882a593Smuzhiyun 	.set_file_size = CIFSSMBSetFileSize,
1188*4882a593Smuzhiyun 	.set_file_info = smb_set_file_info,
1189*4882a593Smuzhiyun 	.set_compression = cifs_set_compression,
1190*4882a593Smuzhiyun 	.echo = CIFSSMBEcho,
1191*4882a593Smuzhiyun 	.mkdir = CIFSSMBMkDir,
1192*4882a593Smuzhiyun 	.mkdir_setinfo = cifs_mkdir_setinfo,
1193*4882a593Smuzhiyun 	.rmdir = CIFSSMBRmDir,
1194*4882a593Smuzhiyun 	.unlink = CIFSSMBDelFile,
1195*4882a593Smuzhiyun 	.rename_pending_delete = cifs_rename_pending_delete,
1196*4882a593Smuzhiyun 	.rename = CIFSSMBRename,
1197*4882a593Smuzhiyun 	.create_hardlink = CIFSCreateHardLink,
1198*4882a593Smuzhiyun 	.query_symlink = cifs_query_symlink,
1199*4882a593Smuzhiyun 	.open = cifs_open_file,
1200*4882a593Smuzhiyun 	.set_fid = cifs_set_fid,
1201*4882a593Smuzhiyun 	.close = cifs_close_file,
1202*4882a593Smuzhiyun 	.flush = cifs_flush_file,
1203*4882a593Smuzhiyun 	.async_readv = cifs_async_readv,
1204*4882a593Smuzhiyun 	.async_writev = cifs_async_writev,
1205*4882a593Smuzhiyun 	.sync_read = cifs_sync_read,
1206*4882a593Smuzhiyun 	.sync_write = cifs_sync_write,
1207*4882a593Smuzhiyun 	.query_dir_first = cifs_query_dir_first,
1208*4882a593Smuzhiyun 	.query_dir_next = cifs_query_dir_next,
1209*4882a593Smuzhiyun 	.close_dir = cifs_close_dir,
1210*4882a593Smuzhiyun 	.calc_smb_size = smbCalcSize,
1211*4882a593Smuzhiyun 	.oplock_response = cifs_oplock_response,
1212*4882a593Smuzhiyun 	.queryfs = cifs_queryfs,
1213*4882a593Smuzhiyun 	.mand_lock = cifs_mand_lock,
1214*4882a593Smuzhiyun 	.mand_unlock_range = cifs_unlock_range,
1215*4882a593Smuzhiyun 	.push_mand_locks = cifs_push_mandatory_locks,
1216*4882a593Smuzhiyun 	.query_mf_symlink = cifs_query_mf_symlink,
1217*4882a593Smuzhiyun 	.create_mf_symlink = cifs_create_mf_symlink,
1218*4882a593Smuzhiyun 	.is_read_op = cifs_is_read_op,
1219*4882a593Smuzhiyun 	.wp_retry_size = cifs_wp_retry_size,
1220*4882a593Smuzhiyun 	.dir_needs_close = cifs_dir_needs_close,
1221*4882a593Smuzhiyun 	.select_sectype = cifs_select_sectype,
1222*4882a593Smuzhiyun #ifdef CONFIG_CIFS_XATTR
1223*4882a593Smuzhiyun 	.query_all_EAs = CIFSSMBQAllEAs,
1224*4882a593Smuzhiyun 	.set_EA = CIFSSMBSetEA,
1225*4882a593Smuzhiyun #endif /* CIFS_XATTR */
1226*4882a593Smuzhiyun 	.get_acl = get_cifs_acl,
1227*4882a593Smuzhiyun 	.get_acl_by_fid = get_cifs_acl_by_fid,
1228*4882a593Smuzhiyun 	.set_acl = set_cifs_acl,
1229*4882a593Smuzhiyun 	.make_node = cifs_make_node,
1230*4882a593Smuzhiyun };
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun struct smb_version_values smb1_values = {
1233*4882a593Smuzhiyun 	.version_string = SMB1_VERSION_STRING,
1234*4882a593Smuzhiyun 	.protocol_id = SMB10_PROT_ID,
1235*4882a593Smuzhiyun 	.large_lock_type = LOCKING_ANDX_LARGE_FILES,
1236*4882a593Smuzhiyun 	.exclusive_lock_type = 0,
1237*4882a593Smuzhiyun 	.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
1238*4882a593Smuzhiyun 	.unlock_lock_type = 0,
1239*4882a593Smuzhiyun 	.header_preamble_size = 4,
1240*4882a593Smuzhiyun 	.header_size = sizeof(struct smb_hdr),
1241*4882a593Smuzhiyun 	.max_header_size = MAX_CIFS_HDR_SIZE,
1242*4882a593Smuzhiyun 	.read_rsp_size = sizeof(READ_RSP),
1243*4882a593Smuzhiyun 	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
1244*4882a593Smuzhiyun 	.cap_unix = CAP_UNIX,
1245*4882a593Smuzhiyun 	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
1246*4882a593Smuzhiyun 	.cap_large_files = CAP_LARGE_FILES,
1247*4882a593Smuzhiyun 	.signing_enabled = SECMODE_SIGN_ENABLED,
1248*4882a593Smuzhiyun 	.signing_required = SECMODE_SIGN_REQUIRED,
1249*4882a593Smuzhiyun };
1250