1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * fs/cifs/connect.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) International Business Machines Corp., 2002,2011
5*4882a593Smuzhiyun * Author(s): Steve French (sfrench@us.ibm.com)
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This library is free software; you can redistribute it and/or modify
8*4882a593Smuzhiyun * it under the terms of the GNU Lesser General Public License as published
9*4882a593Smuzhiyun * by the Free Software Foundation; either version 2.1 of the License, or
10*4882a593Smuzhiyun * (at your option) any later version.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * This library is distributed in the hope that it will be useful,
13*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15*4882a593Smuzhiyun * the GNU Lesser General Public License for more details.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * You should have received a copy of the GNU Lesser General Public License
18*4882a593Smuzhiyun * along with this library; if not, write to the Free Software
19*4882a593Smuzhiyun * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20*4882a593Smuzhiyun */
21*4882a593Smuzhiyun #include <linux/fs.h>
22*4882a593Smuzhiyun #include <linux/net.h>
23*4882a593Smuzhiyun #include <linux/string.h>
24*4882a593Smuzhiyun #include <linux/sched/mm.h>
25*4882a593Smuzhiyun #include <linux/sched/signal.h>
26*4882a593Smuzhiyun #include <linux/list.h>
27*4882a593Smuzhiyun #include <linux/wait.h>
28*4882a593Smuzhiyun #include <linux/slab.h>
29*4882a593Smuzhiyun #include <linux/pagemap.h>
30*4882a593Smuzhiyun #include <linux/ctype.h>
31*4882a593Smuzhiyun #include <linux/utsname.h>
32*4882a593Smuzhiyun #include <linux/mempool.h>
33*4882a593Smuzhiyun #include <linux/delay.h>
34*4882a593Smuzhiyun #include <linux/completion.h>
35*4882a593Smuzhiyun #include <linux/kthread.h>
36*4882a593Smuzhiyun #include <linux/pagevec.h>
37*4882a593Smuzhiyun #include <linux/freezer.h>
38*4882a593Smuzhiyun #include <linux/namei.h>
39*4882a593Smuzhiyun #include <linux/uuid.h>
40*4882a593Smuzhiyun #include <linux/uaccess.h>
41*4882a593Smuzhiyun #include <asm/processor.h>
42*4882a593Smuzhiyun #include <linux/inet.h>
43*4882a593Smuzhiyun #include <linux/module.h>
44*4882a593Smuzhiyun #include <keys/user-type.h>
45*4882a593Smuzhiyun #include <net/ipv6.h>
46*4882a593Smuzhiyun #include <linux/parser.h>
47*4882a593Smuzhiyun #include <linux/bvec.h>
48*4882a593Smuzhiyun #include "cifspdu.h"
49*4882a593Smuzhiyun #include "cifsglob.h"
50*4882a593Smuzhiyun #include "cifsproto.h"
51*4882a593Smuzhiyun #include "cifs_unicode.h"
52*4882a593Smuzhiyun #include "cifs_debug.h"
53*4882a593Smuzhiyun #include "cifs_fs_sb.h"
54*4882a593Smuzhiyun #include "ntlmssp.h"
55*4882a593Smuzhiyun #include "nterr.h"
56*4882a593Smuzhiyun #include "rfc1002pdu.h"
57*4882a593Smuzhiyun #include "fscache.h"
58*4882a593Smuzhiyun #include "smb2proto.h"
59*4882a593Smuzhiyun #include "smbdirect.h"
60*4882a593Smuzhiyun #include "dns_resolve.h"
61*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
62*4882a593Smuzhiyun #include "dfs_cache.h"
63*4882a593Smuzhiyun #endif
64*4882a593Smuzhiyun #include "fs_context.h"
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun extern mempool_t *cifs_req_poolp;
67*4882a593Smuzhiyun extern bool disable_legacy_dialects;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* FIXME: should these be tunable? */
70*4882a593Smuzhiyun #define TLINK_ERROR_EXPIRE (1 * HZ)
71*4882a593Smuzhiyun #define TLINK_IDLE_EXPIRE (600 * HZ)
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Drop the connection to not overload the server */
74*4882a593Smuzhiyun #define NUM_STATUS_IO_TIMEOUT 5
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun enum {
77*4882a593Smuzhiyun /* Mount options that take no arguments */
78*4882a593Smuzhiyun Opt_user_xattr, Opt_nouser_xattr,
79*4882a593Smuzhiyun Opt_forceuid, Opt_noforceuid,
80*4882a593Smuzhiyun Opt_forcegid, Opt_noforcegid,
81*4882a593Smuzhiyun Opt_noblocksend, Opt_noautotune, Opt_nolease,
82*4882a593Smuzhiyun Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete,
83*4882a593Smuzhiyun Opt_mapposix, Opt_nomapposix,
84*4882a593Smuzhiyun Opt_mapchars, Opt_nomapchars, Opt_sfu,
85*4882a593Smuzhiyun Opt_nosfu, Opt_nodfs, Opt_posixpaths,
86*4882a593Smuzhiyun Opt_noposixpaths, Opt_nounix, Opt_unix,
87*4882a593Smuzhiyun Opt_nocase,
88*4882a593Smuzhiyun Opt_brl, Opt_nobrl,
89*4882a593Smuzhiyun Opt_handlecache, Opt_nohandlecache,
90*4882a593Smuzhiyun Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids,
91*4882a593Smuzhiyun Opt_nosetuids, Opt_dynperm, Opt_nodynperm,
92*4882a593Smuzhiyun Opt_nohard, Opt_nosoft,
93*4882a593Smuzhiyun Opt_nointr, Opt_intr,
94*4882a593Smuzhiyun Opt_nostrictsync, Opt_strictsync,
95*4882a593Smuzhiyun Opt_serverino, Opt_noserverino,
96*4882a593Smuzhiyun Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
97*4882a593Smuzhiyun Opt_acl, Opt_noacl, Opt_locallease,
98*4882a593Smuzhiyun Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac,
99*4882a593Smuzhiyun Opt_fsc, Opt_mfsymlinks,
100*4882a593Smuzhiyun Opt_multiuser, Opt_sloppy, Opt_nosharesock,
101*4882a593Smuzhiyun Opt_persistent, Opt_nopersistent,
102*4882a593Smuzhiyun Opt_resilient, Opt_noresilient,
103*4882a593Smuzhiyun Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs,
104*4882a593Smuzhiyun Opt_multichannel, Opt_nomultichannel,
105*4882a593Smuzhiyun Opt_compress,
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* Mount options which take numeric value */
108*4882a593Smuzhiyun Opt_backupuid, Opt_backupgid, Opt_uid,
109*4882a593Smuzhiyun Opt_cruid, Opt_gid, Opt_file_mode,
110*4882a593Smuzhiyun Opt_dirmode, Opt_port,
111*4882a593Smuzhiyun Opt_min_enc_offload,
112*4882a593Smuzhiyun Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
113*4882a593Smuzhiyun Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
114*4882a593Smuzhiyun Opt_snapshot, Opt_max_channels,
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* Mount options which take string value */
117*4882a593Smuzhiyun Opt_user, Opt_pass, Opt_ip,
118*4882a593Smuzhiyun Opt_domain, Opt_srcaddr, Opt_iocharset,
119*4882a593Smuzhiyun Opt_netbiosname, Opt_servern,
120*4882a593Smuzhiyun Opt_ver, Opt_vers, Opt_sec, Opt_cache,
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* Mount options to be ignored */
123*4882a593Smuzhiyun Opt_ignore,
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* Options which could be blank */
126*4882a593Smuzhiyun Opt_blank_pass,
127*4882a593Smuzhiyun Opt_blank_user,
128*4882a593Smuzhiyun Opt_blank_ip,
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun Opt_err
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun static const match_table_t cifs_mount_option_tokens = {
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun { Opt_user_xattr, "user_xattr" },
136*4882a593Smuzhiyun { Opt_nouser_xattr, "nouser_xattr" },
137*4882a593Smuzhiyun { Opt_forceuid, "forceuid" },
138*4882a593Smuzhiyun { Opt_noforceuid, "noforceuid" },
139*4882a593Smuzhiyun { Opt_forcegid, "forcegid" },
140*4882a593Smuzhiyun { Opt_noforcegid, "noforcegid" },
141*4882a593Smuzhiyun { Opt_noblocksend, "noblocksend" },
142*4882a593Smuzhiyun { Opt_noautotune, "noautotune" },
143*4882a593Smuzhiyun { Opt_nolease, "nolease" },
144*4882a593Smuzhiyun { Opt_hard, "hard" },
145*4882a593Smuzhiyun { Opt_soft, "soft" },
146*4882a593Smuzhiyun { Opt_perm, "perm" },
147*4882a593Smuzhiyun { Opt_noperm, "noperm" },
148*4882a593Smuzhiyun { Opt_nodelete, "nodelete" },
149*4882a593Smuzhiyun { Opt_mapchars, "mapchars" }, /* SFU style */
150*4882a593Smuzhiyun { Opt_nomapchars, "nomapchars" },
151*4882a593Smuzhiyun { Opt_mapposix, "mapposix" }, /* SFM style */
152*4882a593Smuzhiyun { Opt_nomapposix, "nomapposix" },
153*4882a593Smuzhiyun { Opt_sfu, "sfu" },
154*4882a593Smuzhiyun { Opt_nosfu, "nosfu" },
155*4882a593Smuzhiyun { Opt_nodfs, "nodfs" },
156*4882a593Smuzhiyun { Opt_posixpaths, "posixpaths" },
157*4882a593Smuzhiyun { Opt_noposixpaths, "noposixpaths" },
158*4882a593Smuzhiyun { Opt_nounix, "nounix" },
159*4882a593Smuzhiyun { Opt_nounix, "nolinux" },
160*4882a593Smuzhiyun { Opt_nounix, "noposix" },
161*4882a593Smuzhiyun { Opt_unix, "unix" },
162*4882a593Smuzhiyun { Opt_unix, "linux" },
163*4882a593Smuzhiyun { Opt_unix, "posix" },
164*4882a593Smuzhiyun { Opt_nocase, "nocase" },
165*4882a593Smuzhiyun { Opt_nocase, "ignorecase" },
166*4882a593Smuzhiyun { Opt_brl, "brl" },
167*4882a593Smuzhiyun { Opt_nobrl, "nobrl" },
168*4882a593Smuzhiyun { Opt_handlecache, "handlecache" },
169*4882a593Smuzhiyun { Opt_nohandlecache, "nohandlecache" },
170*4882a593Smuzhiyun { Opt_nobrl, "nolock" },
171*4882a593Smuzhiyun { Opt_forcemandatorylock, "forcemandatorylock" },
172*4882a593Smuzhiyun { Opt_forcemandatorylock, "forcemand" },
173*4882a593Smuzhiyun { Opt_setuids, "setuids" },
174*4882a593Smuzhiyun { Opt_nosetuids, "nosetuids" },
175*4882a593Smuzhiyun { Opt_setuidfromacl, "idsfromsid" },
176*4882a593Smuzhiyun { Opt_dynperm, "dynperm" },
177*4882a593Smuzhiyun { Opt_nodynperm, "nodynperm" },
178*4882a593Smuzhiyun { Opt_nohard, "nohard" },
179*4882a593Smuzhiyun { Opt_nosoft, "nosoft" },
180*4882a593Smuzhiyun { Opt_nointr, "nointr" },
181*4882a593Smuzhiyun { Opt_intr, "intr" },
182*4882a593Smuzhiyun { Opt_nostrictsync, "nostrictsync" },
183*4882a593Smuzhiyun { Opt_strictsync, "strictsync" },
184*4882a593Smuzhiyun { Opt_serverino, "serverino" },
185*4882a593Smuzhiyun { Opt_noserverino, "noserverino" },
186*4882a593Smuzhiyun { Opt_rwpidforward, "rwpidforward" },
187*4882a593Smuzhiyun { Opt_modesid, "modefromsid" },
188*4882a593Smuzhiyun { Opt_cifsacl, "cifsacl" },
189*4882a593Smuzhiyun { Opt_nocifsacl, "nocifsacl" },
190*4882a593Smuzhiyun { Opt_acl, "acl" },
191*4882a593Smuzhiyun { Opt_noacl, "noacl" },
192*4882a593Smuzhiyun { Opt_locallease, "locallease" },
193*4882a593Smuzhiyun { Opt_sign, "sign" },
194*4882a593Smuzhiyun { Opt_ignore_signature, "signloosely" },
195*4882a593Smuzhiyun { Opt_seal, "seal" },
196*4882a593Smuzhiyun { Opt_noac, "noac" },
197*4882a593Smuzhiyun { Opt_fsc, "fsc" },
198*4882a593Smuzhiyun { Opt_mfsymlinks, "mfsymlinks" },
199*4882a593Smuzhiyun { Opt_multiuser, "multiuser" },
200*4882a593Smuzhiyun { Opt_sloppy, "sloppy" },
201*4882a593Smuzhiyun { Opt_nosharesock, "nosharesock" },
202*4882a593Smuzhiyun { Opt_persistent, "persistenthandles"},
203*4882a593Smuzhiyun { Opt_nopersistent, "nopersistenthandles"},
204*4882a593Smuzhiyun { Opt_resilient, "resilienthandles"},
205*4882a593Smuzhiyun { Opt_noresilient, "noresilienthandles"},
206*4882a593Smuzhiyun { Opt_domainauto, "domainauto"},
207*4882a593Smuzhiyun { Opt_rdma, "rdma"},
208*4882a593Smuzhiyun { Opt_multichannel, "multichannel" },
209*4882a593Smuzhiyun { Opt_nomultichannel, "nomultichannel" },
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun { Opt_backupuid, "backupuid=%s" },
212*4882a593Smuzhiyun { Opt_backupgid, "backupgid=%s" },
213*4882a593Smuzhiyun { Opt_uid, "uid=%s" },
214*4882a593Smuzhiyun { Opt_cruid, "cruid=%s" },
215*4882a593Smuzhiyun { Opt_gid, "gid=%s" },
216*4882a593Smuzhiyun { Opt_file_mode, "file_mode=%s" },
217*4882a593Smuzhiyun { Opt_dirmode, "dirmode=%s" },
218*4882a593Smuzhiyun { Opt_dirmode, "dir_mode=%s" },
219*4882a593Smuzhiyun { Opt_port, "port=%s" },
220*4882a593Smuzhiyun { Opt_min_enc_offload, "esize=%s" },
221*4882a593Smuzhiyun { Opt_blocksize, "bsize=%s" },
222*4882a593Smuzhiyun { Opt_rsize, "rsize=%s" },
223*4882a593Smuzhiyun { Opt_wsize, "wsize=%s" },
224*4882a593Smuzhiyun { Opt_actimeo, "actimeo=%s" },
225*4882a593Smuzhiyun { Opt_handletimeout, "handletimeout=%s" },
226*4882a593Smuzhiyun { Opt_echo_interval, "echo_interval=%s" },
227*4882a593Smuzhiyun { Opt_max_credits, "max_credits=%s" },
228*4882a593Smuzhiyun { Opt_snapshot, "snapshot=%s" },
229*4882a593Smuzhiyun { Opt_max_channels, "max_channels=%s" },
230*4882a593Smuzhiyun { Opt_compress, "compress=%s" },
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun { Opt_blank_user, "user=" },
233*4882a593Smuzhiyun { Opt_blank_user, "username=" },
234*4882a593Smuzhiyun { Opt_user, "user=%s" },
235*4882a593Smuzhiyun { Opt_user, "username=%s" },
236*4882a593Smuzhiyun { Opt_blank_pass, "pass=" },
237*4882a593Smuzhiyun { Opt_blank_pass, "password=" },
238*4882a593Smuzhiyun { Opt_pass, "pass=%s" },
239*4882a593Smuzhiyun { Opt_pass, "password=%s" },
240*4882a593Smuzhiyun { Opt_blank_ip, "ip=" },
241*4882a593Smuzhiyun { Opt_blank_ip, "addr=" },
242*4882a593Smuzhiyun { Opt_ip, "ip=%s" },
243*4882a593Smuzhiyun { Opt_ip, "addr=%s" },
244*4882a593Smuzhiyun { Opt_ignore, "unc=%s" },
245*4882a593Smuzhiyun { Opt_ignore, "target=%s" },
246*4882a593Smuzhiyun { Opt_ignore, "path=%s" },
247*4882a593Smuzhiyun { Opt_domain, "dom=%s" },
248*4882a593Smuzhiyun { Opt_domain, "domain=%s" },
249*4882a593Smuzhiyun { Opt_domain, "workgroup=%s" },
250*4882a593Smuzhiyun { Opt_srcaddr, "srcaddr=%s" },
251*4882a593Smuzhiyun { Opt_ignore, "prefixpath=%s" },
252*4882a593Smuzhiyun { Opt_iocharset, "iocharset=%s" },
253*4882a593Smuzhiyun { Opt_netbiosname, "netbiosname=%s" },
254*4882a593Smuzhiyun { Opt_servern, "servern=%s" },
255*4882a593Smuzhiyun { Opt_ver, "ver=%s" },
256*4882a593Smuzhiyun { Opt_vers, "vers=%s" },
257*4882a593Smuzhiyun { Opt_sec, "sec=%s" },
258*4882a593Smuzhiyun { Opt_cache, "cache=%s" },
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun { Opt_ignore, "cred" },
261*4882a593Smuzhiyun { Opt_ignore, "credentials" },
262*4882a593Smuzhiyun { Opt_ignore, "cred=%s" },
263*4882a593Smuzhiyun { Opt_ignore, "credentials=%s" },
264*4882a593Smuzhiyun { Opt_ignore, "guest" },
265*4882a593Smuzhiyun { Opt_ignore, "rw" },
266*4882a593Smuzhiyun { Opt_ignore, "ro" },
267*4882a593Smuzhiyun { Opt_ignore, "suid" },
268*4882a593Smuzhiyun { Opt_ignore, "nosuid" },
269*4882a593Smuzhiyun { Opt_ignore, "exec" },
270*4882a593Smuzhiyun { Opt_ignore, "noexec" },
271*4882a593Smuzhiyun { Opt_ignore, "nodev" },
272*4882a593Smuzhiyun { Opt_ignore, "noauto" },
273*4882a593Smuzhiyun { Opt_ignore, "dev" },
274*4882a593Smuzhiyun { Opt_ignore, "mand" },
275*4882a593Smuzhiyun { Opt_ignore, "nomand" },
276*4882a593Smuzhiyun { Opt_ignore, "relatime" },
277*4882a593Smuzhiyun { Opt_ignore, "_netdev" },
278*4882a593Smuzhiyun { Opt_rootfs, "rootfs" },
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun { Opt_err, NULL }
281*4882a593Smuzhiyun };
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun static int ip_connect(struct TCP_Server_Info *server);
284*4882a593Smuzhiyun static int generic_ip_connect(struct TCP_Server_Info *server);
285*4882a593Smuzhiyun static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
286*4882a593Smuzhiyun static void cifs_prune_tlinks(struct work_struct *work);
287*4882a593Smuzhiyun static char *extract_hostname(const char *unc);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /*
290*4882a593Smuzhiyun * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
291*4882a593Smuzhiyun * get their ip addresses changed at some point.
292*4882a593Smuzhiyun *
293*4882a593Smuzhiyun * This should be called with server->srv_mutex held.
294*4882a593Smuzhiyun */
295*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
reconn_set_ipaddr(struct TCP_Server_Info * server)296*4882a593Smuzhiyun static int reconn_set_ipaddr(struct TCP_Server_Info *server)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun int rc;
299*4882a593Smuzhiyun int len;
300*4882a593Smuzhiyun char *unc, *ipaddr = NULL;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (!server->hostname)
303*4882a593Smuzhiyun return -EINVAL;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun len = strlen(server->hostname) + 3;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun unc = kmalloc(len, GFP_KERNEL);
308*4882a593Smuzhiyun if (!unc) {
309*4882a593Smuzhiyun cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
310*4882a593Smuzhiyun return -ENOMEM;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun scnprintf(unc, len, "\\\\%s", server->hostname);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
315*4882a593Smuzhiyun kfree(unc);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (rc < 0) {
318*4882a593Smuzhiyun cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
319*4882a593Smuzhiyun __func__, server->hostname, rc);
320*4882a593Smuzhiyun return rc;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
324*4882a593Smuzhiyun rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
325*4882a593Smuzhiyun strlen(ipaddr));
326*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
327*4882a593Smuzhiyun kfree(ipaddr);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return !rc ? -1 : 0;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun #else
reconn_set_ipaddr(struct TCP_Server_Info * server)332*4882a593Smuzhiyun static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun return 0;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun #endif
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
339*4882a593Smuzhiyun /* These functions must be called with server->srv_mutex held */
reconn_set_next_dfs_target(struct TCP_Server_Info * server,struct cifs_sb_info * cifs_sb,struct dfs_cache_tgt_list * tgt_list,struct dfs_cache_tgt_iterator ** tgt_it)340*4882a593Smuzhiyun static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,
341*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb,
342*4882a593Smuzhiyun struct dfs_cache_tgt_list *tgt_list,
343*4882a593Smuzhiyun struct dfs_cache_tgt_iterator **tgt_it)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun const char *name;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (!cifs_sb || !cifs_sb->origin_fullpath)
348*4882a593Smuzhiyun return;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (!*tgt_it) {
351*4882a593Smuzhiyun *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
352*4882a593Smuzhiyun } else {
353*4882a593Smuzhiyun *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
354*4882a593Smuzhiyun if (!*tgt_it)
355*4882a593Smuzhiyun *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun name = dfs_cache_get_tgt_name(*tgt_it);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun kfree(server->hostname);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun server->hostname = extract_hostname(name);
365*4882a593Smuzhiyun if (IS_ERR(server->hostname)) {
366*4882a593Smuzhiyun cifs_dbg(FYI,
367*4882a593Smuzhiyun "%s: failed to extract hostname from target: %ld\n",
368*4882a593Smuzhiyun __func__, PTR_ERR(server->hostname));
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
reconn_setup_dfs_targets(struct cifs_sb_info * cifs_sb,struct dfs_cache_tgt_list * tl)372*4882a593Smuzhiyun static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb,
373*4882a593Smuzhiyun struct dfs_cache_tgt_list *tl)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun if (!cifs_sb->origin_fullpath)
376*4882a593Smuzhiyun return -EOPNOTSUPP;
377*4882a593Smuzhiyun return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun #endif
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /*
382*4882a593Smuzhiyun * cifs tcp session reconnection
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * mark tcp session as reconnecting so temporarily locked
385*4882a593Smuzhiyun * mark all smb sessions as reconnecting for tcp session
386*4882a593Smuzhiyun * reconnect tcp session
387*4882a593Smuzhiyun * wake up waiters on reconnection? - (not needed currently)
388*4882a593Smuzhiyun */
389*4882a593Smuzhiyun int
cifs_reconnect(struct TCP_Server_Info * server)390*4882a593Smuzhiyun cifs_reconnect(struct TCP_Server_Info *server)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun int rc = 0;
393*4882a593Smuzhiyun struct list_head *tmp, *tmp2;
394*4882a593Smuzhiyun struct cifs_ses *ses;
395*4882a593Smuzhiyun struct cifs_tcon *tcon;
396*4882a593Smuzhiyun struct mid_q_entry *mid_entry;
397*4882a593Smuzhiyun struct list_head retry_list;
398*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
399*4882a593Smuzhiyun struct super_block *sb = NULL;
400*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb = NULL;
401*4882a593Smuzhiyun struct dfs_cache_tgt_list tgt_list = {0};
402*4882a593Smuzhiyun struct dfs_cache_tgt_iterator *tgt_it = NULL;
403*4882a593Smuzhiyun #endif
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
406*4882a593Smuzhiyun server->nr_targets = 1;
407*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
408*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
409*4882a593Smuzhiyun sb = cifs_get_tcp_super(server);
410*4882a593Smuzhiyun if (IS_ERR(sb)) {
411*4882a593Smuzhiyun rc = PTR_ERR(sb);
412*4882a593Smuzhiyun cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
413*4882a593Smuzhiyun __func__, rc);
414*4882a593Smuzhiyun sb = NULL;
415*4882a593Smuzhiyun } else {
416*4882a593Smuzhiyun cifs_sb = CIFS_SB(sb);
417*4882a593Smuzhiyun rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list);
418*4882a593Smuzhiyun if (rc) {
419*4882a593Smuzhiyun cifs_sb = NULL;
420*4882a593Smuzhiyun if (rc != -EOPNOTSUPP) {
421*4882a593Smuzhiyun cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
422*4882a593Smuzhiyun __func__);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun } else {
425*4882a593Smuzhiyun server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__,
429*4882a593Smuzhiyun server->nr_targets);
430*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
431*4882a593Smuzhiyun #endif
432*4882a593Smuzhiyun if (server->tcpStatus == CifsExiting) {
433*4882a593Smuzhiyun /* the demux thread will exit normally
434*4882a593Smuzhiyun next time through the loop */
435*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
436*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
437*4882a593Smuzhiyun dfs_cache_free_tgts(&tgt_list);
438*4882a593Smuzhiyun cifs_put_tcp_super(sb);
439*4882a593Smuzhiyun #endif
440*4882a593Smuzhiyun wake_up(&server->response_q);
441*4882a593Smuzhiyun return rc;
442*4882a593Smuzhiyun } else
443*4882a593Smuzhiyun server->tcpStatus = CifsNeedReconnect;
444*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
445*4882a593Smuzhiyun server->maxBuf = 0;
446*4882a593Smuzhiyun server->max_read = 0;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
449*4882a593Smuzhiyun trace_smb3_reconnect(server->CurrentMid, server->hostname);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* before reconnecting the tcp session, mark the smb session (uid)
452*4882a593Smuzhiyun and the tid bad so they are not used until reconnected */
453*4882a593Smuzhiyun cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
454*4882a593Smuzhiyun __func__);
455*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
456*4882a593Smuzhiyun list_for_each(tmp, &server->smb_ses_list) {
457*4882a593Smuzhiyun ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
458*4882a593Smuzhiyun ses->need_reconnect = true;
459*4882a593Smuzhiyun list_for_each(tmp2, &ses->tcon_list) {
460*4882a593Smuzhiyun tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
461*4882a593Smuzhiyun tcon->need_reconnect = true;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun if (ses->tcon_ipc)
464*4882a593Smuzhiyun ses->tcon_ipc->need_reconnect = true;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* do not want to be sending data on a socket we are freeing */
469*4882a593Smuzhiyun cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
470*4882a593Smuzhiyun mutex_lock(&server->srv_mutex);
471*4882a593Smuzhiyun if (server->ssocket) {
472*4882a593Smuzhiyun cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
473*4882a593Smuzhiyun server->ssocket->state, server->ssocket->flags);
474*4882a593Smuzhiyun kernel_sock_shutdown(server->ssocket, SHUT_WR);
475*4882a593Smuzhiyun cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
476*4882a593Smuzhiyun server->ssocket->state, server->ssocket->flags);
477*4882a593Smuzhiyun sock_release(server->ssocket);
478*4882a593Smuzhiyun server->ssocket = NULL;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun server->sequence_number = 0;
481*4882a593Smuzhiyun server->session_estab = false;
482*4882a593Smuzhiyun kfree(server->session_key.response);
483*4882a593Smuzhiyun server->session_key.response = NULL;
484*4882a593Smuzhiyun server->session_key.len = 0;
485*4882a593Smuzhiyun server->lstrp = jiffies;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /* mark submitted MIDs for retry and issue callback */
488*4882a593Smuzhiyun INIT_LIST_HEAD(&retry_list);
489*4882a593Smuzhiyun cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
490*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
491*4882a593Smuzhiyun list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
492*4882a593Smuzhiyun mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
493*4882a593Smuzhiyun kref_get(&mid_entry->refcount);
494*4882a593Smuzhiyun if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
495*4882a593Smuzhiyun mid_entry->mid_state = MID_RETRY_NEEDED;
496*4882a593Smuzhiyun list_move(&mid_entry->qhead, &retry_list);
497*4882a593Smuzhiyun mid_entry->mid_flags |= MID_DELETED;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
500*4882a593Smuzhiyun mutex_unlock(&server->srv_mutex);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
503*4882a593Smuzhiyun list_for_each_safe(tmp, tmp2, &retry_list) {
504*4882a593Smuzhiyun mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
505*4882a593Smuzhiyun list_del_init(&mid_entry->qhead);
506*4882a593Smuzhiyun mid_entry->callback(mid_entry);
507*4882a593Smuzhiyun cifs_mid_q_entry_release(mid_entry);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (cifs_rdma_enabled(server)) {
511*4882a593Smuzhiyun mutex_lock(&server->srv_mutex);
512*4882a593Smuzhiyun smbd_destroy(server);
513*4882a593Smuzhiyun mutex_unlock(&server->srv_mutex);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun do {
517*4882a593Smuzhiyun try_to_freeze();
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun mutex_lock(&server->srv_mutex);
520*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
521*4882a593Smuzhiyun /*
522*4882a593Smuzhiyun * Set up next DFS target server (if any) for reconnect. If DFS
523*4882a593Smuzhiyun * feature is disabled, then we will retry last server we
524*4882a593Smuzhiyun * connected to before.
525*4882a593Smuzhiyun */
526*4882a593Smuzhiyun reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it);
527*4882a593Smuzhiyun #endif
528*4882a593Smuzhiyun rc = reconn_set_ipaddr(server);
529*4882a593Smuzhiyun if (rc) {
530*4882a593Smuzhiyun cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
531*4882a593Smuzhiyun __func__, rc);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (cifs_rdma_enabled(server))
535*4882a593Smuzhiyun rc = smbd_reconnect(server);
536*4882a593Smuzhiyun else
537*4882a593Smuzhiyun rc = generic_ip_connect(server);
538*4882a593Smuzhiyun if (rc) {
539*4882a593Smuzhiyun cifs_dbg(FYI, "reconnect error %d\n", rc);
540*4882a593Smuzhiyun mutex_unlock(&server->srv_mutex);
541*4882a593Smuzhiyun msleep(3000);
542*4882a593Smuzhiyun } else {
543*4882a593Smuzhiyun atomic_inc(&tcpSesReconnectCount);
544*4882a593Smuzhiyun set_credits(server, 1);
545*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
546*4882a593Smuzhiyun if (server->tcpStatus != CifsExiting)
547*4882a593Smuzhiyun server->tcpStatus = CifsNeedNegotiate;
548*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
549*4882a593Smuzhiyun mutex_unlock(&server->srv_mutex);
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun } while (server->tcpStatus == CifsNeedReconnect);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
554*4882a593Smuzhiyun if (tgt_it) {
555*4882a593Smuzhiyun rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
556*4882a593Smuzhiyun tgt_it);
557*4882a593Smuzhiyun if (rc) {
558*4882a593Smuzhiyun cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
559*4882a593Smuzhiyun __func__, rc);
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
562*4882a593Smuzhiyun if (rc) {
563*4882a593Smuzhiyun cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
564*4882a593Smuzhiyun __func__, rc);
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun dfs_cache_free_tgts(&tgt_list);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun cifs_put_tcp_super(sb);
571*4882a593Smuzhiyun #endif
572*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedNegotiate)
573*4882a593Smuzhiyun mod_delayed_work(cifsiod_wq, &server->echo, 0);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun wake_up(&server->response_q);
576*4882a593Smuzhiyun return rc;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun static void
cifs_echo_request(struct work_struct * work)580*4882a593Smuzhiyun cifs_echo_request(struct work_struct *work)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun int rc;
583*4882a593Smuzhiyun struct TCP_Server_Info *server = container_of(work,
584*4882a593Smuzhiyun struct TCP_Server_Info, echo.work);
585*4882a593Smuzhiyun unsigned long echo_interval;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun /*
588*4882a593Smuzhiyun * If we need to renegotiate, set echo interval to zero to
589*4882a593Smuzhiyun * immediately call echo service where we can renegotiate.
590*4882a593Smuzhiyun */
591*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedNegotiate)
592*4882a593Smuzhiyun echo_interval = 0;
593*4882a593Smuzhiyun else
594*4882a593Smuzhiyun echo_interval = server->echo_interval;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /*
597*4882a593Smuzhiyun * We cannot send an echo if it is disabled.
598*4882a593Smuzhiyun * Also, no need to ping if we got a response recently.
599*4882a593Smuzhiyun */
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedReconnect ||
602*4882a593Smuzhiyun server->tcpStatus == CifsExiting ||
603*4882a593Smuzhiyun server->tcpStatus == CifsNew ||
604*4882a593Smuzhiyun (server->ops->can_echo && !server->ops->can_echo(server)) ||
605*4882a593Smuzhiyun time_before(jiffies, server->lstrp + echo_interval - HZ))
606*4882a593Smuzhiyun goto requeue_echo;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
609*4882a593Smuzhiyun if (rc)
610*4882a593Smuzhiyun cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
611*4882a593Smuzhiyun server->hostname);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun requeue_echo:
614*4882a593Smuzhiyun queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun static bool
allocate_buffers(struct TCP_Server_Info * server)618*4882a593Smuzhiyun allocate_buffers(struct TCP_Server_Info *server)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun if (!server->bigbuf) {
621*4882a593Smuzhiyun server->bigbuf = (char *)cifs_buf_get();
622*4882a593Smuzhiyun if (!server->bigbuf) {
623*4882a593Smuzhiyun cifs_server_dbg(VFS, "No memory for large SMB response\n");
624*4882a593Smuzhiyun msleep(3000);
625*4882a593Smuzhiyun /* retry will check if exiting */
626*4882a593Smuzhiyun return false;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun } else if (server->large_buf) {
629*4882a593Smuzhiyun /* we are reusing a dirty large buf, clear its start */
630*4882a593Smuzhiyun memset(server->bigbuf, 0, HEADER_SIZE(server));
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun if (!server->smallbuf) {
634*4882a593Smuzhiyun server->smallbuf = (char *)cifs_small_buf_get();
635*4882a593Smuzhiyun if (!server->smallbuf) {
636*4882a593Smuzhiyun cifs_server_dbg(VFS, "No memory for SMB response\n");
637*4882a593Smuzhiyun msleep(1000);
638*4882a593Smuzhiyun /* retry will check if exiting */
639*4882a593Smuzhiyun return false;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun /* beginning of smb buffer is cleared in our buf_get */
642*4882a593Smuzhiyun } else {
643*4882a593Smuzhiyun /* if existing small buf clear beginning */
644*4882a593Smuzhiyun memset(server->smallbuf, 0, HEADER_SIZE(server));
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun return true;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun static bool
server_unresponsive(struct TCP_Server_Info * server)651*4882a593Smuzhiyun server_unresponsive(struct TCP_Server_Info *server)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun /*
654*4882a593Smuzhiyun * We need to wait 3 echo intervals to make sure we handle such
655*4882a593Smuzhiyun * situations right:
656*4882a593Smuzhiyun * 1s client sends a normal SMB request
657*4882a593Smuzhiyun * 2s client gets a response
658*4882a593Smuzhiyun * 30s echo workqueue job pops, and decides we got a response recently
659*4882a593Smuzhiyun * and don't need to send another
660*4882a593Smuzhiyun * ...
661*4882a593Smuzhiyun * 65s kernel_recvmsg times out, and we see that we haven't gotten
662*4882a593Smuzhiyun * a response in >60s.
663*4882a593Smuzhiyun */
664*4882a593Smuzhiyun if ((server->tcpStatus == CifsGood ||
665*4882a593Smuzhiyun server->tcpStatus == CifsNeedNegotiate) &&
666*4882a593Smuzhiyun (!server->ops->can_echo || server->ops->can_echo(server)) &&
667*4882a593Smuzhiyun time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
668*4882a593Smuzhiyun cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
669*4882a593Smuzhiyun (3 * server->echo_interval) / HZ);
670*4882a593Smuzhiyun cifs_reconnect(server);
671*4882a593Smuzhiyun return true;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun return false;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun static inline bool
zero_credits(struct TCP_Server_Info * server)678*4882a593Smuzhiyun zero_credits(struct TCP_Server_Info *server)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun int val;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun spin_lock(&server->req_lock);
683*4882a593Smuzhiyun val = server->credits + server->echo_credits + server->oplock_credits;
684*4882a593Smuzhiyun if (server->in_flight == 0 && val == 0) {
685*4882a593Smuzhiyun spin_unlock(&server->req_lock);
686*4882a593Smuzhiyun return true;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun spin_unlock(&server->req_lock);
689*4882a593Smuzhiyun return false;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun static int
cifs_readv_from_socket(struct TCP_Server_Info * server,struct msghdr * smb_msg)693*4882a593Smuzhiyun cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun int length = 0;
696*4882a593Smuzhiyun int total_read;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
699*4882a593Smuzhiyun try_to_freeze();
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun /* reconnect if no credits and no requests in flight */
702*4882a593Smuzhiyun if (zero_credits(server)) {
703*4882a593Smuzhiyun cifs_reconnect(server);
704*4882a593Smuzhiyun return -ECONNABORTED;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun if (server_unresponsive(server))
708*4882a593Smuzhiyun return -ECONNABORTED;
709*4882a593Smuzhiyun if (cifs_rdma_enabled(server) && server->smbd_conn)
710*4882a593Smuzhiyun length = smbd_recv(server->smbd_conn, smb_msg);
711*4882a593Smuzhiyun else
712*4882a593Smuzhiyun length = sock_recvmsg(server->ssocket, smb_msg, 0);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun if (server->tcpStatus == CifsExiting)
715*4882a593Smuzhiyun return -ESHUTDOWN;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedReconnect) {
718*4882a593Smuzhiyun cifs_reconnect(server);
719*4882a593Smuzhiyun return -ECONNABORTED;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun if (length == -ERESTARTSYS ||
723*4882a593Smuzhiyun length == -EAGAIN ||
724*4882a593Smuzhiyun length == -EINTR) {
725*4882a593Smuzhiyun /*
726*4882a593Smuzhiyun * Minimum sleep to prevent looping, allowing socket
727*4882a593Smuzhiyun * to clear and app threads to set tcpStatus
728*4882a593Smuzhiyun * CifsNeedReconnect if server hung.
729*4882a593Smuzhiyun */
730*4882a593Smuzhiyun usleep_range(1000, 2000);
731*4882a593Smuzhiyun length = 0;
732*4882a593Smuzhiyun continue;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun if (length <= 0) {
736*4882a593Smuzhiyun cifs_dbg(FYI, "Received no data or error: %d\n", length);
737*4882a593Smuzhiyun cifs_reconnect(server);
738*4882a593Smuzhiyun return -ECONNABORTED;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun return total_read;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun int
cifs_read_from_socket(struct TCP_Server_Info * server,char * buf,unsigned int to_read)745*4882a593Smuzhiyun cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
746*4882a593Smuzhiyun unsigned int to_read)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun struct msghdr smb_msg = {};
749*4882a593Smuzhiyun struct kvec iov = {.iov_base = buf, .iov_len = to_read};
750*4882a593Smuzhiyun iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun return cifs_readv_from_socket(server, &smb_msg);
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun ssize_t
cifs_discard_from_socket(struct TCP_Server_Info * server,size_t to_read)756*4882a593Smuzhiyun cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun struct msghdr smb_msg = {};
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun /*
761*4882a593Smuzhiyun * iov_iter_discard already sets smb_msg.type and count and iov_offset
762*4882a593Smuzhiyun * and cifs_readv_from_socket sets msg_control and msg_controllen
763*4882a593Smuzhiyun * so little to initialize in struct msghdr
764*4882a593Smuzhiyun */
765*4882a593Smuzhiyun iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun return cifs_readv_from_socket(server, &smb_msg);
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun int
cifs_read_page_from_socket(struct TCP_Server_Info * server,struct page * page,unsigned int page_offset,unsigned int to_read)771*4882a593Smuzhiyun cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
772*4882a593Smuzhiyun unsigned int page_offset, unsigned int to_read)
773*4882a593Smuzhiyun {
774*4882a593Smuzhiyun struct msghdr smb_msg = {};
775*4882a593Smuzhiyun struct bio_vec bv = {
776*4882a593Smuzhiyun .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
777*4882a593Smuzhiyun iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
778*4882a593Smuzhiyun return cifs_readv_from_socket(server, &smb_msg);
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun static bool
is_smb_response(struct TCP_Server_Info * server,unsigned char type)782*4882a593Smuzhiyun is_smb_response(struct TCP_Server_Info *server, unsigned char type)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun /*
785*4882a593Smuzhiyun * The first byte big endian of the length field,
786*4882a593Smuzhiyun * is actually not part of the length but the type
787*4882a593Smuzhiyun * with the most common, zero, as regular data.
788*4882a593Smuzhiyun */
789*4882a593Smuzhiyun switch (type) {
790*4882a593Smuzhiyun case RFC1002_SESSION_MESSAGE:
791*4882a593Smuzhiyun /* Regular SMB response */
792*4882a593Smuzhiyun return true;
793*4882a593Smuzhiyun case RFC1002_SESSION_KEEP_ALIVE:
794*4882a593Smuzhiyun cifs_dbg(FYI, "RFC 1002 session keep alive\n");
795*4882a593Smuzhiyun break;
796*4882a593Smuzhiyun case RFC1002_POSITIVE_SESSION_RESPONSE:
797*4882a593Smuzhiyun cifs_dbg(FYI, "RFC 1002 positive session response\n");
798*4882a593Smuzhiyun break;
799*4882a593Smuzhiyun case RFC1002_NEGATIVE_SESSION_RESPONSE:
800*4882a593Smuzhiyun /*
801*4882a593Smuzhiyun * We get this from Windows 98 instead of an error on
802*4882a593Smuzhiyun * SMB negprot response.
803*4882a593Smuzhiyun */
804*4882a593Smuzhiyun cifs_dbg(FYI, "RFC 1002 negative session response\n");
805*4882a593Smuzhiyun /* give server a second to clean up */
806*4882a593Smuzhiyun msleep(1000);
807*4882a593Smuzhiyun /*
808*4882a593Smuzhiyun * Always try 445 first on reconnect since we get NACK
809*4882a593Smuzhiyun * on some if we ever connected to port 139 (the NACK
810*4882a593Smuzhiyun * is since we do not begin with RFC1001 session
811*4882a593Smuzhiyun * initialize frame).
812*4882a593Smuzhiyun */
813*4882a593Smuzhiyun cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
814*4882a593Smuzhiyun cifs_reconnect(server);
815*4882a593Smuzhiyun break;
816*4882a593Smuzhiyun default:
817*4882a593Smuzhiyun cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
818*4882a593Smuzhiyun cifs_reconnect(server);
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun return false;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun void
dequeue_mid(struct mid_q_entry * mid,bool malformed)825*4882a593Smuzhiyun dequeue_mid(struct mid_q_entry *mid, bool malformed)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun #ifdef CONFIG_CIFS_STATS2
828*4882a593Smuzhiyun mid->when_received = jiffies;
829*4882a593Smuzhiyun #endif
830*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
831*4882a593Smuzhiyun if (!malformed)
832*4882a593Smuzhiyun mid->mid_state = MID_RESPONSE_RECEIVED;
833*4882a593Smuzhiyun else
834*4882a593Smuzhiyun mid->mid_state = MID_RESPONSE_MALFORMED;
835*4882a593Smuzhiyun /*
836*4882a593Smuzhiyun * Trying to handle/dequeue a mid after the send_recv()
837*4882a593Smuzhiyun * function has finished processing it is a bug.
838*4882a593Smuzhiyun */
839*4882a593Smuzhiyun if (mid->mid_flags & MID_DELETED)
840*4882a593Smuzhiyun pr_warn_once("trying to dequeue a deleted mid\n");
841*4882a593Smuzhiyun else {
842*4882a593Smuzhiyun list_del_init(&mid->qhead);
843*4882a593Smuzhiyun mid->mid_flags |= MID_DELETED;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun static unsigned int
smb2_get_credits_from_hdr(char * buffer,struct TCP_Server_Info * server)849*4882a593Smuzhiyun smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun /*
854*4882a593Smuzhiyun * SMB1 does not use credits.
855*4882a593Smuzhiyun */
856*4882a593Smuzhiyun if (server->vals->header_preamble_size)
857*4882a593Smuzhiyun return 0;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun return le16_to_cpu(shdr->CreditRequest);
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun static void
handle_mid(struct mid_q_entry * mid,struct TCP_Server_Info * server,char * buf,int malformed)863*4882a593Smuzhiyun handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
864*4882a593Smuzhiyun char *buf, int malformed)
865*4882a593Smuzhiyun {
866*4882a593Smuzhiyun if (server->ops->check_trans2 &&
867*4882a593Smuzhiyun server->ops->check_trans2(mid, server, buf, malformed))
868*4882a593Smuzhiyun return;
869*4882a593Smuzhiyun mid->credits_received = smb2_get_credits_from_hdr(buf, server);
870*4882a593Smuzhiyun mid->resp_buf = buf;
871*4882a593Smuzhiyun mid->large_buf = server->large_buf;
872*4882a593Smuzhiyun /* Was previous buf put in mpx struct for multi-rsp? */
873*4882a593Smuzhiyun if (!mid->multiRsp) {
874*4882a593Smuzhiyun /* smb buffer will be freed by user thread */
875*4882a593Smuzhiyun if (server->large_buf)
876*4882a593Smuzhiyun server->bigbuf = NULL;
877*4882a593Smuzhiyun else
878*4882a593Smuzhiyun server->smallbuf = NULL;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun dequeue_mid(mid, malformed);
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun
clean_demultiplex_info(struct TCP_Server_Info * server)883*4882a593Smuzhiyun static void clean_demultiplex_info(struct TCP_Server_Info *server)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun int length;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun /* take it off the list, if it's not already */
888*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
889*4882a593Smuzhiyun list_del_init(&server->tcp_ses_list);
890*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun cancel_delayed_work_sync(&server->echo);
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
895*4882a593Smuzhiyun server->tcpStatus = CifsExiting;
896*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
897*4882a593Smuzhiyun wake_up_all(&server->response_q);
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /* check if we have blocked requests that need to free */
900*4882a593Smuzhiyun spin_lock(&server->req_lock);
901*4882a593Smuzhiyun if (server->credits <= 0)
902*4882a593Smuzhiyun server->credits = 1;
903*4882a593Smuzhiyun spin_unlock(&server->req_lock);
904*4882a593Smuzhiyun /*
905*4882a593Smuzhiyun * Although there should not be any requests blocked on this queue it
906*4882a593Smuzhiyun * can not hurt to be paranoid and try to wake up requests that may
907*4882a593Smuzhiyun * haven been blocked when more than 50 at time were on the wire to the
908*4882a593Smuzhiyun * same server - they now will see the session is in exit state and get
909*4882a593Smuzhiyun * out of SendReceive.
910*4882a593Smuzhiyun */
911*4882a593Smuzhiyun wake_up_all(&server->request_q);
912*4882a593Smuzhiyun /* give those requests time to exit */
913*4882a593Smuzhiyun msleep(125);
914*4882a593Smuzhiyun if (cifs_rdma_enabled(server))
915*4882a593Smuzhiyun smbd_destroy(server);
916*4882a593Smuzhiyun if (server->ssocket) {
917*4882a593Smuzhiyun sock_release(server->ssocket);
918*4882a593Smuzhiyun server->ssocket = NULL;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (!list_empty(&server->pending_mid_q)) {
922*4882a593Smuzhiyun struct list_head dispose_list;
923*4882a593Smuzhiyun struct mid_q_entry *mid_entry;
924*4882a593Smuzhiyun struct list_head *tmp, *tmp2;
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun INIT_LIST_HEAD(&dispose_list);
927*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
928*4882a593Smuzhiyun list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
929*4882a593Smuzhiyun mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
930*4882a593Smuzhiyun cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid);
931*4882a593Smuzhiyun kref_get(&mid_entry->refcount);
932*4882a593Smuzhiyun mid_entry->mid_state = MID_SHUTDOWN;
933*4882a593Smuzhiyun list_move(&mid_entry->qhead, &dispose_list);
934*4882a593Smuzhiyun mid_entry->mid_flags |= MID_DELETED;
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun /* now walk dispose list and issue callbacks */
939*4882a593Smuzhiyun list_for_each_safe(tmp, tmp2, &dispose_list) {
940*4882a593Smuzhiyun mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
941*4882a593Smuzhiyun cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid);
942*4882a593Smuzhiyun list_del_init(&mid_entry->qhead);
943*4882a593Smuzhiyun mid_entry->callback(mid_entry);
944*4882a593Smuzhiyun cifs_mid_q_entry_release(mid_entry);
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun /* 1/8th of sec is more than enough time for them to exit */
947*4882a593Smuzhiyun msleep(125);
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun if (!list_empty(&server->pending_mid_q)) {
951*4882a593Smuzhiyun /*
952*4882a593Smuzhiyun * mpx threads have not exited yet give them at least the smb
953*4882a593Smuzhiyun * send timeout time for long ops.
954*4882a593Smuzhiyun *
955*4882a593Smuzhiyun * Due to delays on oplock break requests, we need to wait at
956*4882a593Smuzhiyun * least 45 seconds before giving up on a request getting a
957*4882a593Smuzhiyun * response and going ahead and killing cifsd.
958*4882a593Smuzhiyun */
959*4882a593Smuzhiyun cifs_dbg(FYI, "Wait for exit from demultiplex thread\n");
960*4882a593Smuzhiyun msleep(46000);
961*4882a593Smuzhiyun /*
962*4882a593Smuzhiyun * If threads still have not exited they are probably never
963*4882a593Smuzhiyun * coming home not much else we can do but free the memory.
964*4882a593Smuzhiyun */
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun kfree(server->hostname);
968*4882a593Smuzhiyun kfree(server);
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun length = atomic_dec_return(&tcpSesAllocCount);
971*4882a593Smuzhiyun if (length > 0)
972*4882a593Smuzhiyun mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun static int
standard_receive3(struct TCP_Server_Info * server,struct mid_q_entry * mid)976*4882a593Smuzhiyun standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
977*4882a593Smuzhiyun {
978*4882a593Smuzhiyun int length;
979*4882a593Smuzhiyun char *buf = server->smallbuf;
980*4882a593Smuzhiyun unsigned int pdu_length = server->pdu_size;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun /* make sure this will fit in a large buffer */
983*4882a593Smuzhiyun if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
984*4882a593Smuzhiyun server->vals->header_preamble_size) {
985*4882a593Smuzhiyun cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
986*4882a593Smuzhiyun cifs_reconnect(server);
987*4882a593Smuzhiyun return -ECONNABORTED;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun /* switch to large buffer if too big for a small one */
991*4882a593Smuzhiyun if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
992*4882a593Smuzhiyun server->large_buf = true;
993*4882a593Smuzhiyun memcpy(server->bigbuf, buf, server->total_read);
994*4882a593Smuzhiyun buf = server->bigbuf;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun /* now read the rest */
998*4882a593Smuzhiyun length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
999*4882a593Smuzhiyun pdu_length - HEADER_SIZE(server) + 1
1000*4882a593Smuzhiyun + server->vals->header_preamble_size);
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun if (length < 0)
1003*4882a593Smuzhiyun return length;
1004*4882a593Smuzhiyun server->total_read += length;
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun dump_smb(buf, server->total_read);
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun return cifs_handle_standard(server, mid);
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun int
cifs_handle_standard(struct TCP_Server_Info * server,struct mid_q_entry * mid)1012*4882a593Smuzhiyun cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
1015*4882a593Smuzhiyun int length;
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun /*
1018*4882a593Smuzhiyun * We know that we received enough to get to the MID as we
1019*4882a593Smuzhiyun * checked the pdu_length earlier. Now check to see
1020*4882a593Smuzhiyun * if the rest of the header is OK. We borrow the length
1021*4882a593Smuzhiyun * var for the rest of the loop to avoid a new stack var.
1022*4882a593Smuzhiyun *
1023*4882a593Smuzhiyun * 48 bytes is enough to display the header and a little bit
1024*4882a593Smuzhiyun * into the payload for debugging purposes.
1025*4882a593Smuzhiyun */
1026*4882a593Smuzhiyun length = server->ops->check_message(buf, server->total_read, server);
1027*4882a593Smuzhiyun if (length != 0)
1028*4882a593Smuzhiyun cifs_dump_mem("Bad SMB: ", buf,
1029*4882a593Smuzhiyun min_t(unsigned int, server->total_read, 48));
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun if (server->ops->is_session_expired &&
1032*4882a593Smuzhiyun server->ops->is_session_expired(buf)) {
1033*4882a593Smuzhiyun cifs_reconnect(server);
1034*4882a593Smuzhiyun return -1;
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun if (server->ops->is_status_pending &&
1038*4882a593Smuzhiyun server->ops->is_status_pending(buf, server))
1039*4882a593Smuzhiyun return -1;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun if (!mid)
1042*4882a593Smuzhiyun return length;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun handle_mid(mid, server, buf, length);
1045*4882a593Smuzhiyun return 0;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun static void
smb2_add_credits_from_hdr(char * buffer,struct TCP_Server_Info * server)1049*4882a593Smuzhiyun smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /*
1054*4882a593Smuzhiyun * SMB1 does not use credits.
1055*4882a593Smuzhiyun */
1056*4882a593Smuzhiyun if (server->vals->header_preamble_size)
1057*4882a593Smuzhiyun return;
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun if (shdr->CreditRequest) {
1060*4882a593Smuzhiyun spin_lock(&server->req_lock);
1061*4882a593Smuzhiyun server->credits += le16_to_cpu(shdr->CreditRequest);
1062*4882a593Smuzhiyun spin_unlock(&server->req_lock);
1063*4882a593Smuzhiyun wake_up(&server->request_q);
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun static int
cifs_demultiplex_thread(void * p)1069*4882a593Smuzhiyun cifs_demultiplex_thread(void *p)
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun int i, num_mids, length;
1072*4882a593Smuzhiyun struct TCP_Server_Info *server = p;
1073*4882a593Smuzhiyun unsigned int pdu_length;
1074*4882a593Smuzhiyun unsigned int next_offset;
1075*4882a593Smuzhiyun char *buf = NULL;
1076*4882a593Smuzhiyun struct task_struct *task_to_wake = NULL;
1077*4882a593Smuzhiyun struct mid_q_entry *mids[MAX_COMPOUND];
1078*4882a593Smuzhiyun char *bufs[MAX_COMPOUND];
1079*4882a593Smuzhiyun unsigned int noreclaim_flag, num_io_timeout = 0;
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun noreclaim_flag = memalloc_noreclaim_save();
1082*4882a593Smuzhiyun cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun length = atomic_inc_return(&tcpSesAllocCount);
1085*4882a593Smuzhiyun if (length > 1)
1086*4882a593Smuzhiyun mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun set_freezable();
1089*4882a593Smuzhiyun allow_kernel_signal(SIGKILL);
1090*4882a593Smuzhiyun while (server->tcpStatus != CifsExiting) {
1091*4882a593Smuzhiyun if (try_to_freeze())
1092*4882a593Smuzhiyun continue;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun if (!allocate_buffers(server))
1095*4882a593Smuzhiyun continue;
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun server->large_buf = false;
1098*4882a593Smuzhiyun buf = server->smallbuf;
1099*4882a593Smuzhiyun pdu_length = 4; /* enough to get RFC1001 header */
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun length = cifs_read_from_socket(server, buf, pdu_length);
1102*4882a593Smuzhiyun if (length < 0)
1103*4882a593Smuzhiyun continue;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun if (server->vals->header_preamble_size == 0)
1106*4882a593Smuzhiyun server->total_read = 0;
1107*4882a593Smuzhiyun else
1108*4882a593Smuzhiyun server->total_read = length;
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun /*
1111*4882a593Smuzhiyun * The right amount was read from socket - 4 bytes,
1112*4882a593Smuzhiyun * so we can now interpret the length field.
1113*4882a593Smuzhiyun */
1114*4882a593Smuzhiyun pdu_length = get_rfc1002_length(buf);
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
1117*4882a593Smuzhiyun if (!is_smb_response(server, buf[0]))
1118*4882a593Smuzhiyun continue;
1119*4882a593Smuzhiyun next_pdu:
1120*4882a593Smuzhiyun server->pdu_size = pdu_length;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun /* make sure we have enough to get to the MID */
1123*4882a593Smuzhiyun if (server->pdu_size < HEADER_SIZE(server) - 1 -
1124*4882a593Smuzhiyun server->vals->header_preamble_size) {
1125*4882a593Smuzhiyun cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
1126*4882a593Smuzhiyun server->pdu_size);
1127*4882a593Smuzhiyun cifs_reconnect(server);
1128*4882a593Smuzhiyun continue;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun /* read down to the MID */
1132*4882a593Smuzhiyun length = cifs_read_from_socket(server,
1133*4882a593Smuzhiyun buf + server->vals->header_preamble_size,
1134*4882a593Smuzhiyun HEADER_SIZE(server) - 1
1135*4882a593Smuzhiyun - server->vals->header_preamble_size);
1136*4882a593Smuzhiyun if (length < 0)
1137*4882a593Smuzhiyun continue;
1138*4882a593Smuzhiyun server->total_read += length;
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun if (server->ops->next_header) {
1141*4882a593Smuzhiyun next_offset = server->ops->next_header(buf);
1142*4882a593Smuzhiyun if (next_offset)
1143*4882a593Smuzhiyun server->pdu_size = next_offset;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun memset(mids, 0, sizeof(mids));
1147*4882a593Smuzhiyun memset(bufs, 0, sizeof(bufs));
1148*4882a593Smuzhiyun num_mids = 0;
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun if (server->ops->is_transform_hdr &&
1151*4882a593Smuzhiyun server->ops->receive_transform &&
1152*4882a593Smuzhiyun server->ops->is_transform_hdr(buf)) {
1153*4882a593Smuzhiyun length = server->ops->receive_transform(server,
1154*4882a593Smuzhiyun mids,
1155*4882a593Smuzhiyun bufs,
1156*4882a593Smuzhiyun &num_mids);
1157*4882a593Smuzhiyun } else {
1158*4882a593Smuzhiyun mids[0] = server->ops->find_mid(server, buf);
1159*4882a593Smuzhiyun bufs[0] = buf;
1160*4882a593Smuzhiyun num_mids = 1;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun if (!mids[0] || !mids[0]->receive)
1163*4882a593Smuzhiyun length = standard_receive3(server, mids[0]);
1164*4882a593Smuzhiyun else
1165*4882a593Smuzhiyun length = mids[0]->receive(server, mids[0]);
1166*4882a593Smuzhiyun }
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun if (length < 0) {
1169*4882a593Smuzhiyun for (i = 0; i < num_mids; i++)
1170*4882a593Smuzhiyun if (mids[i])
1171*4882a593Smuzhiyun cifs_mid_q_entry_release(mids[i]);
1172*4882a593Smuzhiyun continue;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun if (server->ops->is_status_io_timeout &&
1176*4882a593Smuzhiyun server->ops->is_status_io_timeout(buf)) {
1177*4882a593Smuzhiyun num_io_timeout++;
1178*4882a593Smuzhiyun if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
1179*4882a593Smuzhiyun cifs_reconnect(server);
1180*4882a593Smuzhiyun num_io_timeout = 0;
1181*4882a593Smuzhiyun continue;
1182*4882a593Smuzhiyun }
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun server->lstrp = jiffies;
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun for (i = 0; i < num_mids; i++) {
1188*4882a593Smuzhiyun if (mids[i] != NULL) {
1189*4882a593Smuzhiyun mids[i]->resp_buf_size = server->pdu_size;
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun if (!mids[i]->multiRsp || mids[i]->multiEnd)
1192*4882a593Smuzhiyun mids[i]->callback(mids[i]);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun cifs_mid_q_entry_release(mids[i]);
1195*4882a593Smuzhiyun } else if (server->ops->is_oplock_break &&
1196*4882a593Smuzhiyun server->ops->is_oplock_break(bufs[i],
1197*4882a593Smuzhiyun server)) {
1198*4882a593Smuzhiyun smb2_add_credits_from_hdr(bufs[i], server);
1199*4882a593Smuzhiyun cifs_dbg(FYI, "Received oplock break\n");
1200*4882a593Smuzhiyun } else {
1201*4882a593Smuzhiyun cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
1202*4882a593Smuzhiyun atomic_read(&midCount));
1203*4882a593Smuzhiyun cifs_dump_mem("Received Data is: ", bufs[i],
1204*4882a593Smuzhiyun HEADER_SIZE(server));
1205*4882a593Smuzhiyun smb2_add_credits_from_hdr(bufs[i], server);
1206*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DEBUG2
1207*4882a593Smuzhiyun if (server->ops->dump_detail)
1208*4882a593Smuzhiyun server->ops->dump_detail(bufs[i],
1209*4882a593Smuzhiyun server);
1210*4882a593Smuzhiyun cifs_dump_mids(server);
1211*4882a593Smuzhiyun #endif /* CIFS_DEBUG2 */
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun if (pdu_length > server->pdu_size) {
1216*4882a593Smuzhiyun if (!allocate_buffers(server))
1217*4882a593Smuzhiyun continue;
1218*4882a593Smuzhiyun pdu_length -= server->pdu_size;
1219*4882a593Smuzhiyun server->total_read = 0;
1220*4882a593Smuzhiyun server->large_buf = false;
1221*4882a593Smuzhiyun buf = server->smallbuf;
1222*4882a593Smuzhiyun goto next_pdu;
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun } /* end while !EXITING */
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun /* buffer usually freed in free_mid - need to free it here on exit */
1227*4882a593Smuzhiyun cifs_buf_release(server->bigbuf);
1228*4882a593Smuzhiyun if (server->smallbuf) /* no sense logging a debug message if NULL */
1229*4882a593Smuzhiyun cifs_small_buf_release(server->smallbuf);
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun task_to_wake = xchg(&server->tsk, NULL);
1232*4882a593Smuzhiyun clean_demultiplex_info(server);
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun /* if server->tsk was NULL then wait for a signal before exiting */
1235*4882a593Smuzhiyun if (!task_to_wake) {
1236*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
1237*4882a593Smuzhiyun while (!signal_pending(current)) {
1238*4882a593Smuzhiyun schedule();
1239*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun set_current_state(TASK_RUNNING);
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun memalloc_noreclaim_restore(noreclaim_flag);
1245*4882a593Smuzhiyun module_put_and_exit(0);
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun /* extract the host portion of the UNC string */
1249*4882a593Smuzhiyun static char *
extract_hostname(const char * unc)1250*4882a593Smuzhiyun extract_hostname(const char *unc)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun const char *src;
1253*4882a593Smuzhiyun char *dst, *delim;
1254*4882a593Smuzhiyun unsigned int len;
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun /* skip double chars at beginning of string */
1257*4882a593Smuzhiyun /* BB: check validity of these bytes? */
1258*4882a593Smuzhiyun if (strlen(unc) < 3)
1259*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1260*4882a593Smuzhiyun for (src = unc; *src && *src == '\\'; src++)
1261*4882a593Smuzhiyun ;
1262*4882a593Smuzhiyun if (!*src)
1263*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1264*4882a593Smuzhiyun
1265*4882a593Smuzhiyun /* delimiter between hostname and sharename is always '\\' now */
1266*4882a593Smuzhiyun delim = strchr(src, '\\');
1267*4882a593Smuzhiyun if (!delim)
1268*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun len = delim - src;
1271*4882a593Smuzhiyun dst = kmalloc((len + 1), GFP_KERNEL);
1272*4882a593Smuzhiyun if (dst == NULL)
1273*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun memcpy(dst, src, len);
1276*4882a593Smuzhiyun dst[len] = '\0';
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun return dst;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
get_option_ul(substring_t args[],unsigned long * option)1281*4882a593Smuzhiyun static int get_option_ul(substring_t args[], unsigned long *option)
1282*4882a593Smuzhiyun {
1283*4882a593Smuzhiyun int rc;
1284*4882a593Smuzhiyun char *string;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun string = match_strdup(args);
1287*4882a593Smuzhiyun if (string == NULL)
1288*4882a593Smuzhiyun return -ENOMEM;
1289*4882a593Smuzhiyun rc = kstrtoul(string, 0, option);
1290*4882a593Smuzhiyun kfree(string);
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun return rc;
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun
get_option_uid(substring_t args[],kuid_t * result)1295*4882a593Smuzhiyun static int get_option_uid(substring_t args[], kuid_t *result)
1296*4882a593Smuzhiyun {
1297*4882a593Smuzhiyun unsigned long value;
1298*4882a593Smuzhiyun kuid_t uid;
1299*4882a593Smuzhiyun int rc;
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun rc = get_option_ul(args, &value);
1302*4882a593Smuzhiyun if (rc)
1303*4882a593Smuzhiyun return rc;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun uid = make_kuid(current_user_ns(), value);
1306*4882a593Smuzhiyun if (!uid_valid(uid))
1307*4882a593Smuzhiyun return -EINVAL;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun *result = uid;
1310*4882a593Smuzhiyun return 0;
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun
get_option_gid(substring_t args[],kgid_t * result)1313*4882a593Smuzhiyun static int get_option_gid(substring_t args[], kgid_t *result)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun unsigned long value;
1316*4882a593Smuzhiyun kgid_t gid;
1317*4882a593Smuzhiyun int rc;
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun rc = get_option_ul(args, &value);
1320*4882a593Smuzhiyun if (rc)
1321*4882a593Smuzhiyun return rc;
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun gid = make_kgid(current_user_ns(), value);
1324*4882a593Smuzhiyun if (!gid_valid(gid))
1325*4882a593Smuzhiyun return -EINVAL;
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun *result = gid;
1328*4882a593Smuzhiyun return 0;
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun /*
1332*4882a593Smuzhiyun * Parse a devname into substrings and populate the vol->UNC and vol->prepath
1333*4882a593Smuzhiyun * fields with the result. Returns 0 on success and an error otherwise.
1334*4882a593Smuzhiyun */
1335*4882a593Smuzhiyun static int
cifs_parse_devname(const char * devname,struct smb_vol * vol)1336*4882a593Smuzhiyun cifs_parse_devname(const char *devname, struct smb_vol *vol)
1337*4882a593Smuzhiyun {
1338*4882a593Smuzhiyun char *pos;
1339*4882a593Smuzhiyun const char *delims = "/\\";
1340*4882a593Smuzhiyun size_t len;
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun if (unlikely(!devname || !*devname)) {
1343*4882a593Smuzhiyun cifs_dbg(VFS, "Device name not specified\n");
1344*4882a593Smuzhiyun return -EINVAL;
1345*4882a593Smuzhiyun }
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun /* make sure we have a valid UNC double delimiter prefix */
1348*4882a593Smuzhiyun len = strspn(devname, delims);
1349*4882a593Smuzhiyun if (len != 2)
1350*4882a593Smuzhiyun return -EINVAL;
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun /* find delimiter between host and sharename */
1353*4882a593Smuzhiyun pos = strpbrk(devname + 2, delims);
1354*4882a593Smuzhiyun if (!pos)
1355*4882a593Smuzhiyun return -EINVAL;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun /* skip past delimiter */
1358*4882a593Smuzhiyun ++pos;
1359*4882a593Smuzhiyun
1360*4882a593Smuzhiyun /* now go until next delimiter or end of string */
1361*4882a593Smuzhiyun len = strcspn(pos, delims);
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun /* move "pos" up to delimiter or NULL */
1364*4882a593Smuzhiyun pos += len;
1365*4882a593Smuzhiyun vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
1366*4882a593Smuzhiyun if (!vol->UNC)
1367*4882a593Smuzhiyun return -ENOMEM;
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun convert_delimiter(vol->UNC, '\\');
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun /* skip any delimiter */
1372*4882a593Smuzhiyun if (*pos == '/' || *pos == '\\')
1373*4882a593Smuzhiyun pos++;
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* If pos is NULL then no prepath */
1376*4882a593Smuzhiyun if (!*pos)
1377*4882a593Smuzhiyun return 0;
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun vol->prepath = kstrdup(pos, GFP_KERNEL);
1380*4882a593Smuzhiyun if (!vol->prepath)
1381*4882a593Smuzhiyun return -ENOMEM;
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun return 0;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun static int
cifs_parse_mount_options(const char * mountdata,const char * devname,struct smb_vol * vol,bool is_smb3)1387*4882a593Smuzhiyun cifs_parse_mount_options(const char *mountdata, const char *devname,
1388*4882a593Smuzhiyun struct smb_vol *vol, bool is_smb3)
1389*4882a593Smuzhiyun {
1390*4882a593Smuzhiyun char *data, *end;
1391*4882a593Smuzhiyun char *mountdata_copy = NULL, *options;
1392*4882a593Smuzhiyun unsigned int temp_len, i, j;
1393*4882a593Smuzhiyun char separator[2];
1394*4882a593Smuzhiyun short int override_uid = -1;
1395*4882a593Smuzhiyun short int override_gid = -1;
1396*4882a593Smuzhiyun bool uid_specified = false;
1397*4882a593Smuzhiyun bool gid_specified = false;
1398*4882a593Smuzhiyun bool sloppy = false;
1399*4882a593Smuzhiyun char *invalid = NULL;
1400*4882a593Smuzhiyun char *nodename = utsname()->nodename;
1401*4882a593Smuzhiyun char *string = NULL;
1402*4882a593Smuzhiyun char *tmp_end, *value;
1403*4882a593Smuzhiyun char delim;
1404*4882a593Smuzhiyun bool got_ip = false;
1405*4882a593Smuzhiyun bool got_version = false;
1406*4882a593Smuzhiyun unsigned short port = 0;
1407*4882a593Smuzhiyun struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun separator[0] = ',';
1410*4882a593Smuzhiyun separator[1] = 0;
1411*4882a593Smuzhiyun delim = separator[0];
1412*4882a593Smuzhiyun
1413*4882a593Smuzhiyun /* ensure we always start with zeroed-out smb_vol */
1414*4882a593Smuzhiyun memset(vol, 0, sizeof(*vol));
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun /*
1417*4882a593Smuzhiyun * does not have to be perfect mapping since field is
1418*4882a593Smuzhiyun * informational, only used for servers that do not support
1419*4882a593Smuzhiyun * port 445 and it can be overridden at mount time
1420*4882a593Smuzhiyun */
1421*4882a593Smuzhiyun memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
1422*4882a593Smuzhiyun for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
1423*4882a593Smuzhiyun vol->source_rfc1001_name[i] = toupper(nodename[i]);
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
1426*4882a593Smuzhiyun /* null target name indicates to use *SMBSERVR default called name
1427*4882a593Smuzhiyun if we end up sending RFC1001 session initialize */
1428*4882a593Smuzhiyun vol->target_rfc1001_name[0] = 0;
1429*4882a593Smuzhiyun vol->cred_uid = current_uid();
1430*4882a593Smuzhiyun vol->linux_uid = current_uid();
1431*4882a593Smuzhiyun vol->linux_gid = current_gid();
1432*4882a593Smuzhiyun vol->bsize = 1024 * 1024; /* can improve cp performance significantly */
1433*4882a593Smuzhiyun /*
1434*4882a593Smuzhiyun * default to SFM style remapping of seven reserved characters
1435*4882a593Smuzhiyun * unless user overrides it or we negotiate CIFS POSIX where
1436*4882a593Smuzhiyun * it is unnecessary. Can not simultaneously use more than one mapping
1437*4882a593Smuzhiyun * since then readdir could list files that open could not open
1438*4882a593Smuzhiyun */
1439*4882a593Smuzhiyun vol->remap = true;
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun /* default to only allowing write access to owner of the mount */
1442*4882a593Smuzhiyun vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
1445*4882a593Smuzhiyun /* default is always to request posix paths. */
1446*4882a593Smuzhiyun vol->posix_paths = 1;
1447*4882a593Smuzhiyun /* default to using server inode numbers where available */
1448*4882a593Smuzhiyun vol->server_ino = 1;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun /* default is to use strict cifs caching semantics */
1451*4882a593Smuzhiyun vol->strict_io = true;
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun vol->actimeo = CIFS_DEF_ACTIMEO;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun /* Most clients set timeout to 0, allows server to use its default */
1456*4882a593Smuzhiyun vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
1459*4882a593Smuzhiyun vol->ops = &smb30_operations;
1460*4882a593Smuzhiyun vol->vals = &smbdefault_values;
1461*4882a593Smuzhiyun
1462*4882a593Smuzhiyun vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun /* default to no multichannel (single server connection) */
1465*4882a593Smuzhiyun vol->multichannel = false;
1466*4882a593Smuzhiyun vol->max_channels = 1;
1467*4882a593Smuzhiyun
1468*4882a593Smuzhiyun if (!mountdata)
1469*4882a593Smuzhiyun goto cifs_parse_mount_err;
1470*4882a593Smuzhiyun
1471*4882a593Smuzhiyun mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL);
1472*4882a593Smuzhiyun if (!mountdata_copy)
1473*4882a593Smuzhiyun goto cifs_parse_mount_err;
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun options = mountdata_copy;
1476*4882a593Smuzhiyun end = options + strlen(options);
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun if (strncmp(options, "sep=", 4) == 0) {
1479*4882a593Smuzhiyun if (options[4] != 0) {
1480*4882a593Smuzhiyun separator[0] = options[4];
1481*4882a593Smuzhiyun options += 5;
1482*4882a593Smuzhiyun } else {
1483*4882a593Smuzhiyun cifs_dbg(FYI, "Null separator not allowed\n");
1484*4882a593Smuzhiyun }
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun vol->backupuid_specified = false; /* no backup intent for a user */
1487*4882a593Smuzhiyun vol->backupgid_specified = false; /* no backup intent for a group */
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun switch (cifs_parse_devname(devname, vol)) {
1490*4882a593Smuzhiyun case 0:
1491*4882a593Smuzhiyun break;
1492*4882a593Smuzhiyun case -ENOMEM:
1493*4882a593Smuzhiyun cifs_dbg(VFS, "Unable to allocate memory for devname\n");
1494*4882a593Smuzhiyun goto cifs_parse_mount_err;
1495*4882a593Smuzhiyun case -EINVAL:
1496*4882a593Smuzhiyun cifs_dbg(VFS, "Malformed UNC in devname\n");
1497*4882a593Smuzhiyun goto cifs_parse_mount_err;
1498*4882a593Smuzhiyun default:
1499*4882a593Smuzhiyun cifs_dbg(VFS, "Unknown error parsing devname\n");
1500*4882a593Smuzhiyun goto cifs_parse_mount_err;
1501*4882a593Smuzhiyun }
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun while ((data = strsep(&options, separator)) != NULL) {
1504*4882a593Smuzhiyun substring_t args[MAX_OPT_ARGS];
1505*4882a593Smuzhiyun unsigned long option;
1506*4882a593Smuzhiyun int token;
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if (!*data)
1509*4882a593Smuzhiyun continue;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun token = match_token(data, cifs_mount_option_tokens, args);
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun switch (token) {
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun /* Ingnore the following */
1516*4882a593Smuzhiyun case Opt_ignore:
1517*4882a593Smuzhiyun break;
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun /* Boolean values */
1520*4882a593Smuzhiyun case Opt_user_xattr:
1521*4882a593Smuzhiyun vol->no_xattr = 0;
1522*4882a593Smuzhiyun break;
1523*4882a593Smuzhiyun case Opt_nouser_xattr:
1524*4882a593Smuzhiyun vol->no_xattr = 1;
1525*4882a593Smuzhiyun break;
1526*4882a593Smuzhiyun case Opt_forceuid:
1527*4882a593Smuzhiyun override_uid = 1;
1528*4882a593Smuzhiyun break;
1529*4882a593Smuzhiyun case Opt_noforceuid:
1530*4882a593Smuzhiyun override_uid = 0;
1531*4882a593Smuzhiyun break;
1532*4882a593Smuzhiyun case Opt_forcegid:
1533*4882a593Smuzhiyun override_gid = 1;
1534*4882a593Smuzhiyun break;
1535*4882a593Smuzhiyun case Opt_noforcegid:
1536*4882a593Smuzhiyun override_gid = 0;
1537*4882a593Smuzhiyun break;
1538*4882a593Smuzhiyun case Opt_noblocksend:
1539*4882a593Smuzhiyun vol->noblocksnd = 1;
1540*4882a593Smuzhiyun break;
1541*4882a593Smuzhiyun case Opt_noautotune:
1542*4882a593Smuzhiyun vol->noautotune = 1;
1543*4882a593Smuzhiyun break;
1544*4882a593Smuzhiyun case Opt_nolease:
1545*4882a593Smuzhiyun vol->no_lease = 1;
1546*4882a593Smuzhiyun break;
1547*4882a593Smuzhiyun case Opt_hard:
1548*4882a593Smuzhiyun vol->retry = 1;
1549*4882a593Smuzhiyun break;
1550*4882a593Smuzhiyun case Opt_soft:
1551*4882a593Smuzhiyun vol->retry = 0;
1552*4882a593Smuzhiyun break;
1553*4882a593Smuzhiyun case Opt_perm:
1554*4882a593Smuzhiyun vol->noperm = 0;
1555*4882a593Smuzhiyun break;
1556*4882a593Smuzhiyun case Opt_noperm:
1557*4882a593Smuzhiyun vol->noperm = 1;
1558*4882a593Smuzhiyun break;
1559*4882a593Smuzhiyun case Opt_nodelete:
1560*4882a593Smuzhiyun vol->nodelete = 1;
1561*4882a593Smuzhiyun break;
1562*4882a593Smuzhiyun case Opt_mapchars:
1563*4882a593Smuzhiyun vol->sfu_remap = true;
1564*4882a593Smuzhiyun vol->remap = false; /* disable SFM mapping */
1565*4882a593Smuzhiyun break;
1566*4882a593Smuzhiyun case Opt_nomapchars:
1567*4882a593Smuzhiyun vol->sfu_remap = false;
1568*4882a593Smuzhiyun break;
1569*4882a593Smuzhiyun case Opt_mapposix:
1570*4882a593Smuzhiyun vol->remap = true;
1571*4882a593Smuzhiyun vol->sfu_remap = false; /* disable SFU mapping */
1572*4882a593Smuzhiyun break;
1573*4882a593Smuzhiyun case Opt_nomapposix:
1574*4882a593Smuzhiyun vol->remap = false;
1575*4882a593Smuzhiyun break;
1576*4882a593Smuzhiyun case Opt_sfu:
1577*4882a593Smuzhiyun vol->sfu_emul = 1;
1578*4882a593Smuzhiyun break;
1579*4882a593Smuzhiyun case Opt_nosfu:
1580*4882a593Smuzhiyun vol->sfu_emul = 0;
1581*4882a593Smuzhiyun break;
1582*4882a593Smuzhiyun case Opt_nodfs:
1583*4882a593Smuzhiyun vol->nodfs = 1;
1584*4882a593Smuzhiyun break;
1585*4882a593Smuzhiyun case Opt_rootfs:
1586*4882a593Smuzhiyun #ifdef CONFIG_CIFS_ROOT
1587*4882a593Smuzhiyun vol->rootfs = true;
1588*4882a593Smuzhiyun #endif
1589*4882a593Smuzhiyun break;
1590*4882a593Smuzhiyun case Opt_posixpaths:
1591*4882a593Smuzhiyun vol->posix_paths = 1;
1592*4882a593Smuzhiyun break;
1593*4882a593Smuzhiyun case Opt_noposixpaths:
1594*4882a593Smuzhiyun vol->posix_paths = 0;
1595*4882a593Smuzhiyun break;
1596*4882a593Smuzhiyun case Opt_nounix:
1597*4882a593Smuzhiyun if (vol->linux_ext)
1598*4882a593Smuzhiyun cifs_dbg(VFS,
1599*4882a593Smuzhiyun "conflicting unix mount options\n");
1600*4882a593Smuzhiyun vol->no_linux_ext = 1;
1601*4882a593Smuzhiyun break;
1602*4882a593Smuzhiyun case Opt_unix:
1603*4882a593Smuzhiyun if (vol->no_linux_ext)
1604*4882a593Smuzhiyun cifs_dbg(VFS,
1605*4882a593Smuzhiyun "conflicting unix mount options\n");
1606*4882a593Smuzhiyun vol->linux_ext = 1;
1607*4882a593Smuzhiyun break;
1608*4882a593Smuzhiyun case Opt_nocase:
1609*4882a593Smuzhiyun vol->nocase = 1;
1610*4882a593Smuzhiyun break;
1611*4882a593Smuzhiyun case Opt_brl:
1612*4882a593Smuzhiyun vol->nobrl = 0;
1613*4882a593Smuzhiyun break;
1614*4882a593Smuzhiyun case Opt_nobrl:
1615*4882a593Smuzhiyun vol->nobrl = 1;
1616*4882a593Smuzhiyun /*
1617*4882a593Smuzhiyun * turn off mandatory locking in mode
1618*4882a593Smuzhiyun * if remote locking is turned off since the
1619*4882a593Smuzhiyun * local vfs will do advisory
1620*4882a593Smuzhiyun */
1621*4882a593Smuzhiyun if (vol->file_mode ==
1622*4882a593Smuzhiyun (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1623*4882a593Smuzhiyun vol->file_mode = S_IALLUGO;
1624*4882a593Smuzhiyun break;
1625*4882a593Smuzhiyun case Opt_nohandlecache:
1626*4882a593Smuzhiyun vol->nohandlecache = 1;
1627*4882a593Smuzhiyun break;
1628*4882a593Smuzhiyun case Opt_handlecache:
1629*4882a593Smuzhiyun vol->nohandlecache = 0;
1630*4882a593Smuzhiyun break;
1631*4882a593Smuzhiyun case Opt_forcemandatorylock:
1632*4882a593Smuzhiyun vol->mand_lock = 1;
1633*4882a593Smuzhiyun break;
1634*4882a593Smuzhiyun case Opt_setuids:
1635*4882a593Smuzhiyun vol->setuids = 1;
1636*4882a593Smuzhiyun break;
1637*4882a593Smuzhiyun case Opt_nosetuids:
1638*4882a593Smuzhiyun vol->setuids = 0;
1639*4882a593Smuzhiyun break;
1640*4882a593Smuzhiyun case Opt_setuidfromacl:
1641*4882a593Smuzhiyun vol->setuidfromacl = 1;
1642*4882a593Smuzhiyun break;
1643*4882a593Smuzhiyun case Opt_dynperm:
1644*4882a593Smuzhiyun vol->dynperm = true;
1645*4882a593Smuzhiyun break;
1646*4882a593Smuzhiyun case Opt_nodynperm:
1647*4882a593Smuzhiyun vol->dynperm = false;
1648*4882a593Smuzhiyun break;
1649*4882a593Smuzhiyun case Opt_nohard:
1650*4882a593Smuzhiyun vol->retry = 0;
1651*4882a593Smuzhiyun break;
1652*4882a593Smuzhiyun case Opt_nosoft:
1653*4882a593Smuzhiyun vol->retry = 1;
1654*4882a593Smuzhiyun break;
1655*4882a593Smuzhiyun case Opt_nointr:
1656*4882a593Smuzhiyun vol->intr = 0;
1657*4882a593Smuzhiyun break;
1658*4882a593Smuzhiyun case Opt_intr:
1659*4882a593Smuzhiyun vol->intr = 1;
1660*4882a593Smuzhiyun break;
1661*4882a593Smuzhiyun case Opt_nostrictsync:
1662*4882a593Smuzhiyun vol->nostrictsync = 1;
1663*4882a593Smuzhiyun break;
1664*4882a593Smuzhiyun case Opt_strictsync:
1665*4882a593Smuzhiyun vol->nostrictsync = 0;
1666*4882a593Smuzhiyun break;
1667*4882a593Smuzhiyun case Opt_serverino:
1668*4882a593Smuzhiyun vol->server_ino = 1;
1669*4882a593Smuzhiyun break;
1670*4882a593Smuzhiyun case Opt_noserverino:
1671*4882a593Smuzhiyun vol->server_ino = 0;
1672*4882a593Smuzhiyun break;
1673*4882a593Smuzhiyun case Opt_rwpidforward:
1674*4882a593Smuzhiyun vol->rwpidforward = 1;
1675*4882a593Smuzhiyun break;
1676*4882a593Smuzhiyun case Opt_modesid:
1677*4882a593Smuzhiyun vol->mode_ace = 1;
1678*4882a593Smuzhiyun break;
1679*4882a593Smuzhiyun case Opt_cifsacl:
1680*4882a593Smuzhiyun vol->cifs_acl = 1;
1681*4882a593Smuzhiyun break;
1682*4882a593Smuzhiyun case Opt_nocifsacl:
1683*4882a593Smuzhiyun vol->cifs_acl = 0;
1684*4882a593Smuzhiyun break;
1685*4882a593Smuzhiyun case Opt_acl:
1686*4882a593Smuzhiyun vol->no_psx_acl = 0;
1687*4882a593Smuzhiyun break;
1688*4882a593Smuzhiyun case Opt_noacl:
1689*4882a593Smuzhiyun vol->no_psx_acl = 1;
1690*4882a593Smuzhiyun break;
1691*4882a593Smuzhiyun case Opt_locallease:
1692*4882a593Smuzhiyun vol->local_lease = 1;
1693*4882a593Smuzhiyun break;
1694*4882a593Smuzhiyun case Opt_sign:
1695*4882a593Smuzhiyun vol->sign = true;
1696*4882a593Smuzhiyun break;
1697*4882a593Smuzhiyun case Opt_ignore_signature:
1698*4882a593Smuzhiyun vol->sign = true;
1699*4882a593Smuzhiyun vol->ignore_signature = true;
1700*4882a593Smuzhiyun break;
1701*4882a593Smuzhiyun case Opt_seal:
1702*4882a593Smuzhiyun /* we do not do the following in secFlags because seal
1703*4882a593Smuzhiyun * is a per tree connection (mount) not a per socket
1704*4882a593Smuzhiyun * or per-smb connection option in the protocol
1705*4882a593Smuzhiyun * vol->secFlg |= CIFSSEC_MUST_SEAL;
1706*4882a593Smuzhiyun */
1707*4882a593Smuzhiyun vol->seal = 1;
1708*4882a593Smuzhiyun break;
1709*4882a593Smuzhiyun case Opt_noac:
1710*4882a593Smuzhiyun pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1711*4882a593Smuzhiyun break;
1712*4882a593Smuzhiyun case Opt_fsc:
1713*4882a593Smuzhiyun #ifndef CONFIG_CIFS_FSCACHE
1714*4882a593Smuzhiyun cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n");
1715*4882a593Smuzhiyun goto cifs_parse_mount_err;
1716*4882a593Smuzhiyun #endif
1717*4882a593Smuzhiyun vol->fsc = true;
1718*4882a593Smuzhiyun break;
1719*4882a593Smuzhiyun case Opt_mfsymlinks:
1720*4882a593Smuzhiyun vol->mfsymlinks = true;
1721*4882a593Smuzhiyun break;
1722*4882a593Smuzhiyun case Opt_multiuser:
1723*4882a593Smuzhiyun vol->multiuser = true;
1724*4882a593Smuzhiyun break;
1725*4882a593Smuzhiyun case Opt_sloppy:
1726*4882a593Smuzhiyun sloppy = true;
1727*4882a593Smuzhiyun break;
1728*4882a593Smuzhiyun case Opt_nosharesock:
1729*4882a593Smuzhiyun vol->nosharesock = true;
1730*4882a593Smuzhiyun break;
1731*4882a593Smuzhiyun case Opt_nopersistent:
1732*4882a593Smuzhiyun vol->nopersistent = true;
1733*4882a593Smuzhiyun if (vol->persistent) {
1734*4882a593Smuzhiyun cifs_dbg(VFS,
1735*4882a593Smuzhiyun "persistenthandles mount options conflict\n");
1736*4882a593Smuzhiyun goto cifs_parse_mount_err;
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun break;
1739*4882a593Smuzhiyun case Opt_persistent:
1740*4882a593Smuzhiyun vol->persistent = true;
1741*4882a593Smuzhiyun if ((vol->nopersistent) || (vol->resilient)) {
1742*4882a593Smuzhiyun cifs_dbg(VFS,
1743*4882a593Smuzhiyun "persistenthandles mount options conflict\n");
1744*4882a593Smuzhiyun goto cifs_parse_mount_err;
1745*4882a593Smuzhiyun }
1746*4882a593Smuzhiyun break;
1747*4882a593Smuzhiyun case Opt_resilient:
1748*4882a593Smuzhiyun vol->resilient = true;
1749*4882a593Smuzhiyun if (vol->persistent) {
1750*4882a593Smuzhiyun cifs_dbg(VFS,
1751*4882a593Smuzhiyun "persistenthandles mount options conflict\n");
1752*4882a593Smuzhiyun goto cifs_parse_mount_err;
1753*4882a593Smuzhiyun }
1754*4882a593Smuzhiyun break;
1755*4882a593Smuzhiyun case Opt_noresilient:
1756*4882a593Smuzhiyun vol->resilient = false; /* already the default */
1757*4882a593Smuzhiyun break;
1758*4882a593Smuzhiyun case Opt_domainauto:
1759*4882a593Smuzhiyun vol->domainauto = true;
1760*4882a593Smuzhiyun break;
1761*4882a593Smuzhiyun case Opt_rdma:
1762*4882a593Smuzhiyun vol->rdma = true;
1763*4882a593Smuzhiyun break;
1764*4882a593Smuzhiyun case Opt_multichannel:
1765*4882a593Smuzhiyun vol->multichannel = true;
1766*4882a593Smuzhiyun /* if number of channels not specified, default to 2 */
1767*4882a593Smuzhiyun if (vol->max_channels < 2)
1768*4882a593Smuzhiyun vol->max_channels = 2;
1769*4882a593Smuzhiyun break;
1770*4882a593Smuzhiyun case Opt_nomultichannel:
1771*4882a593Smuzhiyun vol->multichannel = false;
1772*4882a593Smuzhiyun vol->max_channels = 1;
1773*4882a593Smuzhiyun break;
1774*4882a593Smuzhiyun case Opt_compress:
1775*4882a593Smuzhiyun vol->compression = UNKNOWN_TYPE;
1776*4882a593Smuzhiyun cifs_dbg(VFS,
1777*4882a593Smuzhiyun "SMB3 compression support is experimental\n");
1778*4882a593Smuzhiyun break;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun /* Numeric Values */
1781*4882a593Smuzhiyun case Opt_backupuid:
1782*4882a593Smuzhiyun if (get_option_uid(args, &vol->backupuid)) {
1783*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid backupuid value\n",
1784*4882a593Smuzhiyun __func__);
1785*4882a593Smuzhiyun goto cifs_parse_mount_err;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun vol->backupuid_specified = true;
1788*4882a593Smuzhiyun break;
1789*4882a593Smuzhiyun case Opt_backupgid:
1790*4882a593Smuzhiyun if (get_option_gid(args, &vol->backupgid)) {
1791*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid backupgid value\n",
1792*4882a593Smuzhiyun __func__);
1793*4882a593Smuzhiyun goto cifs_parse_mount_err;
1794*4882a593Smuzhiyun }
1795*4882a593Smuzhiyun vol->backupgid_specified = true;
1796*4882a593Smuzhiyun break;
1797*4882a593Smuzhiyun case Opt_uid:
1798*4882a593Smuzhiyun if (get_option_uid(args, &vol->linux_uid)) {
1799*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid uid value\n",
1800*4882a593Smuzhiyun __func__);
1801*4882a593Smuzhiyun goto cifs_parse_mount_err;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun uid_specified = true;
1804*4882a593Smuzhiyun break;
1805*4882a593Smuzhiyun case Opt_cruid:
1806*4882a593Smuzhiyun if (get_option_uid(args, &vol->cred_uid)) {
1807*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid cruid value\n",
1808*4882a593Smuzhiyun __func__);
1809*4882a593Smuzhiyun goto cifs_parse_mount_err;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun break;
1812*4882a593Smuzhiyun case Opt_gid:
1813*4882a593Smuzhiyun if (get_option_gid(args, &vol->linux_gid)) {
1814*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid gid value\n",
1815*4882a593Smuzhiyun __func__);
1816*4882a593Smuzhiyun goto cifs_parse_mount_err;
1817*4882a593Smuzhiyun }
1818*4882a593Smuzhiyun gid_specified = true;
1819*4882a593Smuzhiyun break;
1820*4882a593Smuzhiyun case Opt_file_mode:
1821*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1822*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid file_mode value\n",
1823*4882a593Smuzhiyun __func__);
1824*4882a593Smuzhiyun goto cifs_parse_mount_err;
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun vol->file_mode = option;
1827*4882a593Smuzhiyun break;
1828*4882a593Smuzhiyun case Opt_dirmode:
1829*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1830*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid dir_mode value\n",
1831*4882a593Smuzhiyun __func__);
1832*4882a593Smuzhiyun goto cifs_parse_mount_err;
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun vol->dir_mode = option;
1835*4882a593Smuzhiyun break;
1836*4882a593Smuzhiyun case Opt_port:
1837*4882a593Smuzhiyun if (get_option_ul(args, &option) ||
1838*4882a593Smuzhiyun option > USHRT_MAX) {
1839*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid port value\n",
1840*4882a593Smuzhiyun __func__);
1841*4882a593Smuzhiyun goto cifs_parse_mount_err;
1842*4882a593Smuzhiyun }
1843*4882a593Smuzhiyun port = (unsigned short)option;
1844*4882a593Smuzhiyun break;
1845*4882a593Smuzhiyun case Opt_min_enc_offload:
1846*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1847*4882a593Smuzhiyun cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n");
1848*4882a593Smuzhiyun goto cifs_parse_mount_err;
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun vol->min_offload = option;
1851*4882a593Smuzhiyun break;
1852*4882a593Smuzhiyun case Opt_blocksize:
1853*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1854*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid blocksize value\n",
1855*4882a593Smuzhiyun __func__);
1856*4882a593Smuzhiyun goto cifs_parse_mount_err;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun /*
1859*4882a593Smuzhiyun * inode blocksize realistically should never need to be
1860*4882a593Smuzhiyun * less than 16K or greater than 16M and default is 1MB.
1861*4882a593Smuzhiyun * Note that small inode block sizes (e.g. 64K) can lead
1862*4882a593Smuzhiyun * to very poor performance of common tools like cp and scp
1863*4882a593Smuzhiyun */
1864*4882a593Smuzhiyun if ((option < CIFS_MAX_MSGSIZE) ||
1865*4882a593Smuzhiyun (option > (4 * SMB3_DEFAULT_IOSIZE))) {
1866*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid blocksize\n",
1867*4882a593Smuzhiyun __func__);
1868*4882a593Smuzhiyun goto cifs_parse_mount_err;
1869*4882a593Smuzhiyun }
1870*4882a593Smuzhiyun vol->bsize = option;
1871*4882a593Smuzhiyun break;
1872*4882a593Smuzhiyun case Opt_rsize:
1873*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1874*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid rsize value\n",
1875*4882a593Smuzhiyun __func__);
1876*4882a593Smuzhiyun goto cifs_parse_mount_err;
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun vol->rsize = option;
1879*4882a593Smuzhiyun break;
1880*4882a593Smuzhiyun case Opt_wsize:
1881*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1882*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid wsize value\n",
1883*4882a593Smuzhiyun __func__);
1884*4882a593Smuzhiyun goto cifs_parse_mount_err;
1885*4882a593Smuzhiyun }
1886*4882a593Smuzhiyun vol->wsize = option;
1887*4882a593Smuzhiyun break;
1888*4882a593Smuzhiyun case Opt_actimeo:
1889*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1890*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid actimeo value\n",
1891*4882a593Smuzhiyun __func__);
1892*4882a593Smuzhiyun goto cifs_parse_mount_err;
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun vol->actimeo = HZ * option;
1895*4882a593Smuzhiyun if (vol->actimeo > CIFS_MAX_ACTIMEO) {
1896*4882a593Smuzhiyun cifs_dbg(VFS, "attribute cache timeout too large\n");
1897*4882a593Smuzhiyun goto cifs_parse_mount_err;
1898*4882a593Smuzhiyun }
1899*4882a593Smuzhiyun break;
1900*4882a593Smuzhiyun case Opt_handletimeout:
1901*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1902*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
1903*4882a593Smuzhiyun __func__);
1904*4882a593Smuzhiyun goto cifs_parse_mount_err;
1905*4882a593Smuzhiyun }
1906*4882a593Smuzhiyun vol->handle_timeout = option;
1907*4882a593Smuzhiyun if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
1908*4882a593Smuzhiyun cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
1909*4882a593Smuzhiyun goto cifs_parse_mount_err;
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun break;
1912*4882a593Smuzhiyun case Opt_echo_interval:
1913*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1914*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid echo interval value\n",
1915*4882a593Smuzhiyun __func__);
1916*4882a593Smuzhiyun goto cifs_parse_mount_err;
1917*4882a593Smuzhiyun }
1918*4882a593Smuzhiyun vol->echo_interval = option;
1919*4882a593Smuzhiyun break;
1920*4882a593Smuzhiyun case Opt_snapshot:
1921*4882a593Smuzhiyun if (get_option_ul(args, &option)) {
1922*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid snapshot time\n",
1923*4882a593Smuzhiyun __func__);
1924*4882a593Smuzhiyun goto cifs_parse_mount_err;
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun vol->snapshot_time = option;
1927*4882a593Smuzhiyun break;
1928*4882a593Smuzhiyun case Opt_max_credits:
1929*4882a593Smuzhiyun if (get_option_ul(args, &option) || (option < 20) ||
1930*4882a593Smuzhiyun (option > 60000)) {
1931*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid max_credits value\n",
1932*4882a593Smuzhiyun __func__);
1933*4882a593Smuzhiyun goto cifs_parse_mount_err;
1934*4882a593Smuzhiyun }
1935*4882a593Smuzhiyun vol->max_credits = option;
1936*4882a593Smuzhiyun break;
1937*4882a593Smuzhiyun case Opt_max_channels:
1938*4882a593Smuzhiyun if (get_option_ul(args, &option) || option < 1 ||
1939*4882a593Smuzhiyun option > CIFS_MAX_CHANNELS) {
1940*4882a593Smuzhiyun cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n",
1941*4882a593Smuzhiyun __func__, CIFS_MAX_CHANNELS);
1942*4882a593Smuzhiyun goto cifs_parse_mount_err;
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun vol->max_channels = option;
1945*4882a593Smuzhiyun break;
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun /* String Arguments */
1948*4882a593Smuzhiyun
1949*4882a593Smuzhiyun case Opt_blank_user:
1950*4882a593Smuzhiyun /* null user, ie. anonymous authentication */
1951*4882a593Smuzhiyun vol->nullauth = 1;
1952*4882a593Smuzhiyun vol->username = NULL;
1953*4882a593Smuzhiyun break;
1954*4882a593Smuzhiyun case Opt_user:
1955*4882a593Smuzhiyun string = match_strdup(args);
1956*4882a593Smuzhiyun if (string == NULL)
1957*4882a593Smuzhiyun goto out_nomem;
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun if (strnlen(string, CIFS_MAX_USERNAME_LEN) >
1960*4882a593Smuzhiyun CIFS_MAX_USERNAME_LEN) {
1961*4882a593Smuzhiyun pr_warn("username too long\n");
1962*4882a593Smuzhiyun goto cifs_parse_mount_err;
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun
1965*4882a593Smuzhiyun kfree(vol->username);
1966*4882a593Smuzhiyun vol->username = kstrdup(string, GFP_KERNEL);
1967*4882a593Smuzhiyun if (!vol->username)
1968*4882a593Smuzhiyun goto cifs_parse_mount_err;
1969*4882a593Smuzhiyun break;
1970*4882a593Smuzhiyun case Opt_blank_pass:
1971*4882a593Smuzhiyun /* passwords have to be handled differently
1972*4882a593Smuzhiyun * to allow the character used for deliminator
1973*4882a593Smuzhiyun * to be passed within them
1974*4882a593Smuzhiyun */
1975*4882a593Smuzhiyun
1976*4882a593Smuzhiyun /*
1977*4882a593Smuzhiyun * Check if this is a case where the password
1978*4882a593Smuzhiyun * starts with a delimiter
1979*4882a593Smuzhiyun */
1980*4882a593Smuzhiyun tmp_end = strchr(data, '=');
1981*4882a593Smuzhiyun tmp_end++;
1982*4882a593Smuzhiyun if (!(tmp_end < end && tmp_end[1] == delim)) {
1983*4882a593Smuzhiyun /* No it is not. Set the password to NULL */
1984*4882a593Smuzhiyun kfree_sensitive(vol->password);
1985*4882a593Smuzhiyun vol->password = NULL;
1986*4882a593Smuzhiyun break;
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun fallthrough; /* to Opt_pass below */
1989*4882a593Smuzhiyun case Opt_pass:
1990*4882a593Smuzhiyun /* Obtain the value string */
1991*4882a593Smuzhiyun value = strchr(data, '=');
1992*4882a593Smuzhiyun value++;
1993*4882a593Smuzhiyun
1994*4882a593Smuzhiyun /* Set tmp_end to end of the string */
1995*4882a593Smuzhiyun tmp_end = (char *) value + strlen(value);
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun /* Check if following character is the deliminator
1998*4882a593Smuzhiyun * If yes, we have encountered a double deliminator
1999*4882a593Smuzhiyun * reset the NULL character to the deliminator
2000*4882a593Smuzhiyun */
2001*4882a593Smuzhiyun if (tmp_end < end && tmp_end[1] == delim) {
2002*4882a593Smuzhiyun tmp_end[0] = delim;
2003*4882a593Smuzhiyun
2004*4882a593Smuzhiyun /* Keep iterating until we get to a single
2005*4882a593Smuzhiyun * deliminator OR the end
2006*4882a593Smuzhiyun */
2007*4882a593Smuzhiyun while ((tmp_end = strchr(tmp_end, delim))
2008*4882a593Smuzhiyun != NULL && (tmp_end[1] == delim)) {
2009*4882a593Smuzhiyun tmp_end = (char *) &tmp_end[2];
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun
2012*4882a593Smuzhiyun /* Reset var options to point to next element */
2013*4882a593Smuzhiyun if (tmp_end) {
2014*4882a593Smuzhiyun tmp_end[0] = '\0';
2015*4882a593Smuzhiyun options = (char *) &tmp_end[1];
2016*4882a593Smuzhiyun } else
2017*4882a593Smuzhiyun /* Reached the end of the mount option
2018*4882a593Smuzhiyun * string */
2019*4882a593Smuzhiyun options = end;
2020*4882a593Smuzhiyun }
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun kfree_sensitive(vol->password);
2023*4882a593Smuzhiyun /* Now build new password string */
2024*4882a593Smuzhiyun temp_len = strlen(value);
2025*4882a593Smuzhiyun vol->password = kzalloc(temp_len+1, GFP_KERNEL);
2026*4882a593Smuzhiyun if (vol->password == NULL) {
2027*4882a593Smuzhiyun pr_warn("no memory for password\n");
2028*4882a593Smuzhiyun goto cifs_parse_mount_err;
2029*4882a593Smuzhiyun }
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun for (i = 0, j = 0; i < temp_len; i++, j++) {
2032*4882a593Smuzhiyun vol->password[j] = value[i];
2033*4882a593Smuzhiyun if ((value[i] == delim) &&
2034*4882a593Smuzhiyun value[i+1] == delim)
2035*4882a593Smuzhiyun /* skip the second deliminator */
2036*4882a593Smuzhiyun i++;
2037*4882a593Smuzhiyun }
2038*4882a593Smuzhiyun vol->password[j] = '\0';
2039*4882a593Smuzhiyun break;
2040*4882a593Smuzhiyun case Opt_blank_ip:
2041*4882a593Smuzhiyun /* FIXME: should this be an error instead? */
2042*4882a593Smuzhiyun got_ip = false;
2043*4882a593Smuzhiyun break;
2044*4882a593Smuzhiyun case Opt_ip:
2045*4882a593Smuzhiyun string = match_strdup(args);
2046*4882a593Smuzhiyun if (string == NULL)
2047*4882a593Smuzhiyun goto out_nomem;
2048*4882a593Smuzhiyun
2049*4882a593Smuzhiyun if (!cifs_convert_address(dstaddr, string,
2050*4882a593Smuzhiyun strlen(string))) {
2051*4882a593Smuzhiyun pr_err("bad ip= option (%s)\n", string);
2052*4882a593Smuzhiyun goto cifs_parse_mount_err;
2053*4882a593Smuzhiyun }
2054*4882a593Smuzhiyun got_ip = true;
2055*4882a593Smuzhiyun break;
2056*4882a593Smuzhiyun case Opt_domain:
2057*4882a593Smuzhiyun string = match_strdup(args);
2058*4882a593Smuzhiyun if (string == NULL)
2059*4882a593Smuzhiyun goto out_nomem;
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
2062*4882a593Smuzhiyun == CIFS_MAX_DOMAINNAME_LEN) {
2063*4882a593Smuzhiyun pr_warn("domain name too long\n");
2064*4882a593Smuzhiyun goto cifs_parse_mount_err;
2065*4882a593Smuzhiyun }
2066*4882a593Smuzhiyun
2067*4882a593Smuzhiyun kfree(vol->domainname);
2068*4882a593Smuzhiyun vol->domainname = kstrdup(string, GFP_KERNEL);
2069*4882a593Smuzhiyun if (!vol->domainname) {
2070*4882a593Smuzhiyun pr_warn("no memory for domainname\n");
2071*4882a593Smuzhiyun goto cifs_parse_mount_err;
2072*4882a593Smuzhiyun }
2073*4882a593Smuzhiyun cifs_dbg(FYI, "Domain name set\n");
2074*4882a593Smuzhiyun break;
2075*4882a593Smuzhiyun case Opt_srcaddr:
2076*4882a593Smuzhiyun string = match_strdup(args);
2077*4882a593Smuzhiyun if (string == NULL)
2078*4882a593Smuzhiyun goto out_nomem;
2079*4882a593Smuzhiyun
2080*4882a593Smuzhiyun if (!cifs_convert_address(
2081*4882a593Smuzhiyun (struct sockaddr *)&vol->srcaddr,
2082*4882a593Smuzhiyun string, strlen(string))) {
2083*4882a593Smuzhiyun pr_warn("Could not parse srcaddr: %s\n",
2084*4882a593Smuzhiyun string);
2085*4882a593Smuzhiyun goto cifs_parse_mount_err;
2086*4882a593Smuzhiyun }
2087*4882a593Smuzhiyun break;
2088*4882a593Smuzhiyun case Opt_iocharset:
2089*4882a593Smuzhiyun string = match_strdup(args);
2090*4882a593Smuzhiyun if (string == NULL)
2091*4882a593Smuzhiyun goto out_nomem;
2092*4882a593Smuzhiyun
2093*4882a593Smuzhiyun if (strnlen(string, 1024) >= 65) {
2094*4882a593Smuzhiyun pr_warn("iocharset name too long\n");
2095*4882a593Smuzhiyun goto cifs_parse_mount_err;
2096*4882a593Smuzhiyun }
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun if (strncasecmp(string, "default", 7) != 0) {
2099*4882a593Smuzhiyun kfree(vol->iocharset);
2100*4882a593Smuzhiyun vol->iocharset = kstrdup(string,
2101*4882a593Smuzhiyun GFP_KERNEL);
2102*4882a593Smuzhiyun if (!vol->iocharset) {
2103*4882a593Smuzhiyun pr_warn("no memory for charset\n");
2104*4882a593Smuzhiyun goto cifs_parse_mount_err;
2105*4882a593Smuzhiyun }
2106*4882a593Smuzhiyun }
2107*4882a593Smuzhiyun /* if iocharset not set then load_nls_default
2108*4882a593Smuzhiyun * is used by caller
2109*4882a593Smuzhiyun */
2110*4882a593Smuzhiyun cifs_dbg(FYI, "iocharset set to %s\n", string);
2111*4882a593Smuzhiyun break;
2112*4882a593Smuzhiyun case Opt_netbiosname:
2113*4882a593Smuzhiyun string = match_strdup(args);
2114*4882a593Smuzhiyun if (string == NULL)
2115*4882a593Smuzhiyun goto out_nomem;
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun memset(vol->source_rfc1001_name, 0x20,
2118*4882a593Smuzhiyun RFC1001_NAME_LEN);
2119*4882a593Smuzhiyun /*
2120*4882a593Smuzhiyun * FIXME: are there cases in which a comma can
2121*4882a593Smuzhiyun * be valid in workstation netbios name (and
2122*4882a593Smuzhiyun * need special handling)?
2123*4882a593Smuzhiyun */
2124*4882a593Smuzhiyun for (i = 0; i < RFC1001_NAME_LEN; i++) {
2125*4882a593Smuzhiyun /* don't ucase netbiosname for user */
2126*4882a593Smuzhiyun if (string[i] == 0)
2127*4882a593Smuzhiyun break;
2128*4882a593Smuzhiyun vol->source_rfc1001_name[i] = string[i];
2129*4882a593Smuzhiyun }
2130*4882a593Smuzhiyun /* The string has 16th byte zero still from
2131*4882a593Smuzhiyun * set at top of the function
2132*4882a593Smuzhiyun */
2133*4882a593Smuzhiyun if (i == RFC1001_NAME_LEN && string[i] != 0)
2134*4882a593Smuzhiyun pr_warn("netbiosname longer than 15 truncated\n");
2135*4882a593Smuzhiyun break;
2136*4882a593Smuzhiyun case Opt_servern:
2137*4882a593Smuzhiyun /* servernetbiosname specified override *SMBSERVER */
2138*4882a593Smuzhiyun string = match_strdup(args);
2139*4882a593Smuzhiyun if (string == NULL)
2140*4882a593Smuzhiyun goto out_nomem;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun /* last byte, type, is 0x20 for servr type */
2143*4882a593Smuzhiyun memset(vol->target_rfc1001_name, 0x20,
2144*4882a593Smuzhiyun RFC1001_NAME_LEN_WITH_NULL);
2145*4882a593Smuzhiyun
2146*4882a593Smuzhiyun /* BB are there cases in which a comma can be
2147*4882a593Smuzhiyun valid in this workstation netbios name
2148*4882a593Smuzhiyun (and need special handling)? */
2149*4882a593Smuzhiyun
2150*4882a593Smuzhiyun /* user or mount helper must uppercase the
2151*4882a593Smuzhiyun netbios name */
2152*4882a593Smuzhiyun for (i = 0; i < 15; i++) {
2153*4882a593Smuzhiyun if (string[i] == 0)
2154*4882a593Smuzhiyun break;
2155*4882a593Smuzhiyun vol->target_rfc1001_name[i] = string[i];
2156*4882a593Smuzhiyun }
2157*4882a593Smuzhiyun /* The string has 16th byte zero still from
2158*4882a593Smuzhiyun set at top of the function */
2159*4882a593Smuzhiyun if (i == RFC1001_NAME_LEN && string[i] != 0)
2160*4882a593Smuzhiyun pr_warn("server netbiosname longer than 15 truncated\n");
2161*4882a593Smuzhiyun break;
2162*4882a593Smuzhiyun case Opt_ver:
2163*4882a593Smuzhiyun /* version of mount userspace tools, not dialect */
2164*4882a593Smuzhiyun string = match_strdup(args);
2165*4882a593Smuzhiyun if (string == NULL)
2166*4882a593Smuzhiyun goto out_nomem;
2167*4882a593Smuzhiyun
2168*4882a593Smuzhiyun /* If interface changes in mount.cifs bump to new ver */
2169*4882a593Smuzhiyun if (strncasecmp(string, "1", 1) == 0) {
2170*4882a593Smuzhiyun if (strlen(string) > 1) {
2171*4882a593Smuzhiyun pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n",
2172*4882a593Smuzhiyun string);
2173*4882a593Smuzhiyun goto cifs_parse_mount_err;
2174*4882a593Smuzhiyun }
2175*4882a593Smuzhiyun /* This is the default */
2176*4882a593Smuzhiyun break;
2177*4882a593Smuzhiyun }
2178*4882a593Smuzhiyun /* For all other value, error */
2179*4882a593Smuzhiyun pr_warn("Invalid mount helper version specified\n");
2180*4882a593Smuzhiyun goto cifs_parse_mount_err;
2181*4882a593Smuzhiyun case Opt_vers:
2182*4882a593Smuzhiyun /* protocol version (dialect) */
2183*4882a593Smuzhiyun string = match_strdup(args);
2184*4882a593Smuzhiyun if (string == NULL)
2185*4882a593Smuzhiyun goto out_nomem;
2186*4882a593Smuzhiyun
2187*4882a593Smuzhiyun if (cifs_parse_smb_version(string, vol, is_smb3) != 0)
2188*4882a593Smuzhiyun goto cifs_parse_mount_err;
2189*4882a593Smuzhiyun got_version = true;
2190*4882a593Smuzhiyun break;
2191*4882a593Smuzhiyun case Opt_sec:
2192*4882a593Smuzhiyun string = match_strdup(args);
2193*4882a593Smuzhiyun if (string == NULL)
2194*4882a593Smuzhiyun goto out_nomem;
2195*4882a593Smuzhiyun
2196*4882a593Smuzhiyun if (cifs_parse_security_flavors(string, vol) != 0)
2197*4882a593Smuzhiyun goto cifs_parse_mount_err;
2198*4882a593Smuzhiyun break;
2199*4882a593Smuzhiyun case Opt_cache:
2200*4882a593Smuzhiyun string = match_strdup(args);
2201*4882a593Smuzhiyun if (string == NULL)
2202*4882a593Smuzhiyun goto out_nomem;
2203*4882a593Smuzhiyun
2204*4882a593Smuzhiyun if (cifs_parse_cache_flavor(string, vol) != 0)
2205*4882a593Smuzhiyun goto cifs_parse_mount_err;
2206*4882a593Smuzhiyun break;
2207*4882a593Smuzhiyun default:
2208*4882a593Smuzhiyun /*
2209*4882a593Smuzhiyun * An option we don't recognize. Save it off for later
2210*4882a593Smuzhiyun * if we haven't already found one
2211*4882a593Smuzhiyun */
2212*4882a593Smuzhiyun if (!invalid)
2213*4882a593Smuzhiyun invalid = data;
2214*4882a593Smuzhiyun break;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun /* Free up any allocated string */
2217*4882a593Smuzhiyun kfree(string);
2218*4882a593Smuzhiyun string = NULL;
2219*4882a593Smuzhiyun }
2220*4882a593Smuzhiyun
2221*4882a593Smuzhiyun if (!sloppy && invalid) {
2222*4882a593Smuzhiyun pr_err("Unknown mount option \"%s\"\n", invalid);
2223*4882a593Smuzhiyun goto cifs_parse_mount_err;
2224*4882a593Smuzhiyun }
2225*4882a593Smuzhiyun
2226*4882a593Smuzhiyun if (vol->rdma && vol->vals->protocol_id < SMB30_PROT_ID) {
2227*4882a593Smuzhiyun cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n");
2228*4882a593Smuzhiyun goto cifs_parse_mount_err;
2229*4882a593Smuzhiyun }
2230*4882a593Smuzhiyun
2231*4882a593Smuzhiyun #ifndef CONFIG_KEYS
2232*4882a593Smuzhiyun /* Muliuser mounts require CONFIG_KEYS support */
2233*4882a593Smuzhiyun if (vol->multiuser) {
2234*4882a593Smuzhiyun cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n");
2235*4882a593Smuzhiyun goto cifs_parse_mount_err;
2236*4882a593Smuzhiyun }
2237*4882a593Smuzhiyun #endif
2238*4882a593Smuzhiyun if (!vol->UNC) {
2239*4882a593Smuzhiyun cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n");
2240*4882a593Smuzhiyun goto cifs_parse_mount_err;
2241*4882a593Smuzhiyun }
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun /* make sure UNC has a share name */
2244*4882a593Smuzhiyun if (!strchr(vol->UNC + 3, '\\')) {
2245*4882a593Smuzhiyun cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n");
2246*4882a593Smuzhiyun goto cifs_parse_mount_err;
2247*4882a593Smuzhiyun }
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun if (!got_ip) {
2250*4882a593Smuzhiyun int len;
2251*4882a593Smuzhiyun const char *slash;
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun /* No ip= option specified? Try to get it from UNC */
2254*4882a593Smuzhiyun /* Use the address part of the UNC. */
2255*4882a593Smuzhiyun slash = strchr(&vol->UNC[2], '\\');
2256*4882a593Smuzhiyun len = slash - &vol->UNC[2];
2257*4882a593Smuzhiyun if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) {
2258*4882a593Smuzhiyun pr_err("Unable to determine destination address\n");
2259*4882a593Smuzhiyun goto cifs_parse_mount_err;
2260*4882a593Smuzhiyun }
2261*4882a593Smuzhiyun }
2262*4882a593Smuzhiyun
2263*4882a593Smuzhiyun /* set the port that we got earlier */
2264*4882a593Smuzhiyun cifs_set_port(dstaddr, port);
2265*4882a593Smuzhiyun
2266*4882a593Smuzhiyun if (uid_specified)
2267*4882a593Smuzhiyun vol->override_uid = override_uid;
2268*4882a593Smuzhiyun else if (override_uid == 1)
2269*4882a593Smuzhiyun pr_notice("ignoring forceuid mount option specified with no uid= option\n");
2270*4882a593Smuzhiyun
2271*4882a593Smuzhiyun if (gid_specified)
2272*4882a593Smuzhiyun vol->override_gid = override_gid;
2273*4882a593Smuzhiyun else if (override_gid == 1)
2274*4882a593Smuzhiyun pr_notice("ignoring forcegid mount option specified with no gid= option\n");
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun if (got_version == false)
2277*4882a593Smuzhiyun pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n");
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun kfree(mountdata_copy);
2280*4882a593Smuzhiyun return 0;
2281*4882a593Smuzhiyun
2282*4882a593Smuzhiyun out_nomem:
2283*4882a593Smuzhiyun pr_warn("Could not allocate temporary buffer\n");
2284*4882a593Smuzhiyun cifs_parse_mount_err:
2285*4882a593Smuzhiyun kfree(string);
2286*4882a593Smuzhiyun kfree(mountdata_copy);
2287*4882a593Smuzhiyun return 1;
2288*4882a593Smuzhiyun }
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun /** Returns true if srcaddr isn't specified and rhs isn't
2291*4882a593Smuzhiyun * specified, or if srcaddr is specified and
2292*4882a593Smuzhiyun * matches the IP address of the rhs argument.
2293*4882a593Smuzhiyun */
2294*4882a593Smuzhiyun bool
cifs_match_ipaddr(struct sockaddr * srcaddr,struct sockaddr * rhs)2295*4882a593Smuzhiyun cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
2296*4882a593Smuzhiyun {
2297*4882a593Smuzhiyun switch (srcaddr->sa_family) {
2298*4882a593Smuzhiyun case AF_UNSPEC:
2299*4882a593Smuzhiyun return (rhs->sa_family == AF_UNSPEC);
2300*4882a593Smuzhiyun case AF_INET: {
2301*4882a593Smuzhiyun struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
2302*4882a593Smuzhiyun struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
2303*4882a593Smuzhiyun return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
2304*4882a593Smuzhiyun }
2305*4882a593Smuzhiyun case AF_INET6: {
2306*4882a593Smuzhiyun struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
2307*4882a593Smuzhiyun struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
2308*4882a593Smuzhiyun return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun default:
2311*4882a593Smuzhiyun WARN_ON(1);
2312*4882a593Smuzhiyun return false; /* don't expect to be here */
2313*4882a593Smuzhiyun }
2314*4882a593Smuzhiyun }
2315*4882a593Smuzhiyun
2316*4882a593Smuzhiyun /*
2317*4882a593Smuzhiyun * If no port is specified in addr structure, we try to match with 445 port
2318*4882a593Smuzhiyun * and if it fails - with 139 ports. It should be called only if address
2319*4882a593Smuzhiyun * families of server and addr are equal.
2320*4882a593Smuzhiyun */
2321*4882a593Smuzhiyun static bool
match_port(struct TCP_Server_Info * server,struct sockaddr * addr)2322*4882a593Smuzhiyun match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
2323*4882a593Smuzhiyun {
2324*4882a593Smuzhiyun __be16 port, *sport;
2325*4882a593Smuzhiyun
2326*4882a593Smuzhiyun /* SMBDirect manages its own ports, don't match it here */
2327*4882a593Smuzhiyun if (server->rdma)
2328*4882a593Smuzhiyun return true;
2329*4882a593Smuzhiyun
2330*4882a593Smuzhiyun switch (addr->sa_family) {
2331*4882a593Smuzhiyun case AF_INET:
2332*4882a593Smuzhiyun sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
2333*4882a593Smuzhiyun port = ((struct sockaddr_in *) addr)->sin_port;
2334*4882a593Smuzhiyun break;
2335*4882a593Smuzhiyun case AF_INET6:
2336*4882a593Smuzhiyun sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
2337*4882a593Smuzhiyun port = ((struct sockaddr_in6 *) addr)->sin6_port;
2338*4882a593Smuzhiyun break;
2339*4882a593Smuzhiyun default:
2340*4882a593Smuzhiyun WARN_ON(1);
2341*4882a593Smuzhiyun return false;
2342*4882a593Smuzhiyun }
2343*4882a593Smuzhiyun
2344*4882a593Smuzhiyun if (!port) {
2345*4882a593Smuzhiyun port = htons(CIFS_PORT);
2346*4882a593Smuzhiyun if (port == *sport)
2347*4882a593Smuzhiyun return true;
2348*4882a593Smuzhiyun
2349*4882a593Smuzhiyun port = htons(RFC1001_PORT);
2350*4882a593Smuzhiyun }
2351*4882a593Smuzhiyun
2352*4882a593Smuzhiyun return port == *sport;
2353*4882a593Smuzhiyun }
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun static bool
match_address(struct TCP_Server_Info * server,struct sockaddr * addr,struct sockaddr * srcaddr)2356*4882a593Smuzhiyun match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
2357*4882a593Smuzhiyun struct sockaddr *srcaddr)
2358*4882a593Smuzhiyun {
2359*4882a593Smuzhiyun switch (addr->sa_family) {
2360*4882a593Smuzhiyun case AF_INET: {
2361*4882a593Smuzhiyun struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
2362*4882a593Smuzhiyun struct sockaddr_in *srv_addr4 =
2363*4882a593Smuzhiyun (struct sockaddr_in *)&server->dstaddr;
2364*4882a593Smuzhiyun
2365*4882a593Smuzhiyun if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
2366*4882a593Smuzhiyun return false;
2367*4882a593Smuzhiyun break;
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun case AF_INET6: {
2370*4882a593Smuzhiyun struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
2371*4882a593Smuzhiyun struct sockaddr_in6 *srv_addr6 =
2372*4882a593Smuzhiyun (struct sockaddr_in6 *)&server->dstaddr;
2373*4882a593Smuzhiyun
2374*4882a593Smuzhiyun if (!ipv6_addr_equal(&addr6->sin6_addr,
2375*4882a593Smuzhiyun &srv_addr6->sin6_addr))
2376*4882a593Smuzhiyun return false;
2377*4882a593Smuzhiyun if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
2378*4882a593Smuzhiyun return false;
2379*4882a593Smuzhiyun break;
2380*4882a593Smuzhiyun }
2381*4882a593Smuzhiyun default:
2382*4882a593Smuzhiyun WARN_ON(1);
2383*4882a593Smuzhiyun return false; /* don't expect to be here */
2384*4882a593Smuzhiyun }
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr))
2387*4882a593Smuzhiyun return false;
2388*4882a593Smuzhiyun
2389*4882a593Smuzhiyun return true;
2390*4882a593Smuzhiyun }
2391*4882a593Smuzhiyun
2392*4882a593Smuzhiyun static bool
match_security(struct TCP_Server_Info * server,struct smb_vol * vol)2393*4882a593Smuzhiyun match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
2394*4882a593Smuzhiyun {
2395*4882a593Smuzhiyun /*
2396*4882a593Smuzhiyun * The select_sectype function should either return the vol->sectype
2397*4882a593Smuzhiyun * that was specified, or "Unspecified" if that sectype was not
2398*4882a593Smuzhiyun * compatible with the given NEGOTIATE request.
2399*4882a593Smuzhiyun */
2400*4882a593Smuzhiyun if (server->ops->select_sectype(server, vol->sectype)
2401*4882a593Smuzhiyun == Unspecified)
2402*4882a593Smuzhiyun return false;
2403*4882a593Smuzhiyun
2404*4882a593Smuzhiyun /*
2405*4882a593Smuzhiyun * Now check if signing mode is acceptable. No need to check
2406*4882a593Smuzhiyun * global_secflags at this point since if MUST_SIGN is set then
2407*4882a593Smuzhiyun * the server->sign had better be too.
2408*4882a593Smuzhiyun */
2409*4882a593Smuzhiyun if (vol->sign && !server->sign)
2410*4882a593Smuzhiyun return false;
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun return true;
2413*4882a593Smuzhiyun }
2414*4882a593Smuzhiyun
match_server(struct TCP_Server_Info * server,struct smb_vol * vol)2415*4882a593Smuzhiyun static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
2416*4882a593Smuzhiyun {
2417*4882a593Smuzhiyun struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr;
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun if (vol->nosharesock)
2420*4882a593Smuzhiyun return 0;
2421*4882a593Smuzhiyun
2422*4882a593Smuzhiyun /* If multidialect negotiation see if existing sessions match one */
2423*4882a593Smuzhiyun if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
2424*4882a593Smuzhiyun if (server->vals->protocol_id < SMB30_PROT_ID)
2425*4882a593Smuzhiyun return 0;
2426*4882a593Smuzhiyun } else if (strcmp(vol->vals->version_string,
2427*4882a593Smuzhiyun SMBDEFAULT_VERSION_STRING) == 0) {
2428*4882a593Smuzhiyun if (server->vals->protocol_id < SMB21_PROT_ID)
2429*4882a593Smuzhiyun return 0;
2430*4882a593Smuzhiyun } else if ((server->vals != vol->vals) || (server->ops != vol->ops))
2431*4882a593Smuzhiyun return 0;
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
2434*4882a593Smuzhiyun return 0;
2435*4882a593Smuzhiyun
2436*4882a593Smuzhiyun if (!match_address(server, addr,
2437*4882a593Smuzhiyun (struct sockaddr *)&vol->srcaddr))
2438*4882a593Smuzhiyun return 0;
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun if (!match_port(server, addr))
2441*4882a593Smuzhiyun return 0;
2442*4882a593Smuzhiyun
2443*4882a593Smuzhiyun if (!match_security(server, vol))
2444*4882a593Smuzhiyun return 0;
2445*4882a593Smuzhiyun
2446*4882a593Smuzhiyun if (server->echo_interval != vol->echo_interval * HZ)
2447*4882a593Smuzhiyun return 0;
2448*4882a593Smuzhiyun
2449*4882a593Smuzhiyun if (server->rdma != vol->rdma)
2450*4882a593Smuzhiyun return 0;
2451*4882a593Smuzhiyun
2452*4882a593Smuzhiyun if (server->ignore_signature != vol->ignore_signature)
2453*4882a593Smuzhiyun return 0;
2454*4882a593Smuzhiyun
2455*4882a593Smuzhiyun if (server->min_offload != vol->min_offload)
2456*4882a593Smuzhiyun return 0;
2457*4882a593Smuzhiyun
2458*4882a593Smuzhiyun return 1;
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun
2461*4882a593Smuzhiyun struct TCP_Server_Info *
cifs_find_tcp_session(struct smb_vol * vol)2462*4882a593Smuzhiyun cifs_find_tcp_session(struct smb_vol *vol)
2463*4882a593Smuzhiyun {
2464*4882a593Smuzhiyun struct TCP_Server_Info *server;
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2467*4882a593Smuzhiyun list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
2468*4882a593Smuzhiyun /*
2469*4882a593Smuzhiyun * Skip ses channels since they're only handled in lower layers
2470*4882a593Smuzhiyun * (e.g. cifs_send_recv).
2471*4882a593Smuzhiyun */
2472*4882a593Smuzhiyun if (server->is_channel || !match_server(server, vol))
2473*4882a593Smuzhiyun continue;
2474*4882a593Smuzhiyun
2475*4882a593Smuzhiyun ++server->srv_count;
2476*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2477*4882a593Smuzhiyun cifs_dbg(FYI, "Existing tcp session with server found\n");
2478*4882a593Smuzhiyun return server;
2479*4882a593Smuzhiyun }
2480*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2481*4882a593Smuzhiyun return NULL;
2482*4882a593Smuzhiyun }
2483*4882a593Smuzhiyun
2484*4882a593Smuzhiyun void
cifs_put_tcp_session(struct TCP_Server_Info * server,int from_reconnect)2485*4882a593Smuzhiyun cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
2486*4882a593Smuzhiyun {
2487*4882a593Smuzhiyun struct task_struct *task;
2488*4882a593Smuzhiyun
2489*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2490*4882a593Smuzhiyun if (--server->srv_count > 0) {
2491*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2492*4882a593Smuzhiyun return;
2493*4882a593Smuzhiyun }
2494*4882a593Smuzhiyun
2495*4882a593Smuzhiyun put_net(cifs_net_ns(server));
2496*4882a593Smuzhiyun
2497*4882a593Smuzhiyun list_del_init(&server->tcp_ses_list);
2498*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2499*4882a593Smuzhiyun
2500*4882a593Smuzhiyun cancel_delayed_work_sync(&server->echo);
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun if (from_reconnect)
2503*4882a593Smuzhiyun /*
2504*4882a593Smuzhiyun * Avoid deadlock here: reconnect work calls
2505*4882a593Smuzhiyun * cifs_put_tcp_session() at its end. Need to be sure
2506*4882a593Smuzhiyun * that reconnect work does nothing with server pointer after
2507*4882a593Smuzhiyun * that step.
2508*4882a593Smuzhiyun */
2509*4882a593Smuzhiyun cancel_delayed_work(&server->reconnect);
2510*4882a593Smuzhiyun else
2511*4882a593Smuzhiyun cancel_delayed_work_sync(&server->reconnect);
2512*4882a593Smuzhiyun
2513*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
2514*4882a593Smuzhiyun server->tcpStatus = CifsExiting;
2515*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
2516*4882a593Smuzhiyun
2517*4882a593Smuzhiyun cifs_crypto_secmech_release(server);
2518*4882a593Smuzhiyun cifs_fscache_release_client_cookie(server);
2519*4882a593Smuzhiyun
2520*4882a593Smuzhiyun kfree(server->session_key.response);
2521*4882a593Smuzhiyun server->session_key.response = NULL;
2522*4882a593Smuzhiyun server->session_key.len = 0;
2523*4882a593Smuzhiyun
2524*4882a593Smuzhiyun task = xchg(&server->tsk, NULL);
2525*4882a593Smuzhiyun if (task)
2526*4882a593Smuzhiyun send_sig(SIGKILL, task, 1);
2527*4882a593Smuzhiyun }
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun struct TCP_Server_Info *
cifs_get_tcp_session(struct smb_vol * volume_info)2530*4882a593Smuzhiyun cifs_get_tcp_session(struct smb_vol *volume_info)
2531*4882a593Smuzhiyun {
2532*4882a593Smuzhiyun struct TCP_Server_Info *tcp_ses = NULL;
2533*4882a593Smuzhiyun int rc;
2534*4882a593Smuzhiyun
2535*4882a593Smuzhiyun cifs_dbg(FYI, "UNC: %s\n", volume_info->UNC);
2536*4882a593Smuzhiyun
2537*4882a593Smuzhiyun /* see if we already have a matching tcp_ses */
2538*4882a593Smuzhiyun tcp_ses = cifs_find_tcp_session(volume_info);
2539*4882a593Smuzhiyun if (tcp_ses)
2540*4882a593Smuzhiyun return tcp_ses;
2541*4882a593Smuzhiyun
2542*4882a593Smuzhiyun tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2543*4882a593Smuzhiyun if (!tcp_ses) {
2544*4882a593Smuzhiyun rc = -ENOMEM;
2545*4882a593Smuzhiyun goto out_err;
2546*4882a593Smuzhiyun }
2547*4882a593Smuzhiyun
2548*4882a593Smuzhiyun tcp_ses->ops = volume_info->ops;
2549*4882a593Smuzhiyun tcp_ses->vals = volume_info->vals;
2550*4882a593Smuzhiyun cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
2551*4882a593Smuzhiyun tcp_ses->hostname = extract_hostname(volume_info->UNC);
2552*4882a593Smuzhiyun if (IS_ERR(tcp_ses->hostname)) {
2553*4882a593Smuzhiyun rc = PTR_ERR(tcp_ses->hostname);
2554*4882a593Smuzhiyun goto out_err_crypto_release;
2555*4882a593Smuzhiyun }
2556*4882a593Smuzhiyun
2557*4882a593Smuzhiyun tcp_ses->noblockcnt = volume_info->rootfs;
2558*4882a593Smuzhiyun tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs;
2559*4882a593Smuzhiyun tcp_ses->noautotune = volume_info->noautotune;
2560*4882a593Smuzhiyun tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
2561*4882a593Smuzhiyun tcp_ses->rdma = volume_info->rdma;
2562*4882a593Smuzhiyun tcp_ses->in_flight = 0;
2563*4882a593Smuzhiyun tcp_ses->max_in_flight = 0;
2564*4882a593Smuzhiyun tcp_ses->credits = 1;
2565*4882a593Smuzhiyun init_waitqueue_head(&tcp_ses->response_q);
2566*4882a593Smuzhiyun init_waitqueue_head(&tcp_ses->request_q);
2567*4882a593Smuzhiyun INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
2568*4882a593Smuzhiyun mutex_init(&tcp_ses->srv_mutex);
2569*4882a593Smuzhiyun memcpy(tcp_ses->workstation_RFC1001_name,
2570*4882a593Smuzhiyun volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
2571*4882a593Smuzhiyun memcpy(tcp_ses->server_RFC1001_name,
2572*4882a593Smuzhiyun volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
2573*4882a593Smuzhiyun tcp_ses->session_estab = false;
2574*4882a593Smuzhiyun tcp_ses->sequence_number = 0;
2575*4882a593Smuzhiyun tcp_ses->reconnect_instance = 1;
2576*4882a593Smuzhiyun tcp_ses->lstrp = jiffies;
2577*4882a593Smuzhiyun tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression);
2578*4882a593Smuzhiyun spin_lock_init(&tcp_ses->req_lock);
2579*4882a593Smuzhiyun INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
2580*4882a593Smuzhiyun INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
2581*4882a593Smuzhiyun INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
2582*4882a593Smuzhiyun INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
2583*4882a593Smuzhiyun mutex_init(&tcp_ses->reconnect_mutex);
2584*4882a593Smuzhiyun memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
2585*4882a593Smuzhiyun sizeof(tcp_ses->srcaddr));
2586*4882a593Smuzhiyun memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
2587*4882a593Smuzhiyun sizeof(tcp_ses->dstaddr));
2588*4882a593Smuzhiyun if (volume_info->use_client_guid)
2589*4882a593Smuzhiyun memcpy(tcp_ses->client_guid, volume_info->client_guid,
2590*4882a593Smuzhiyun SMB2_CLIENT_GUID_SIZE);
2591*4882a593Smuzhiyun else
2592*4882a593Smuzhiyun generate_random_uuid(tcp_ses->client_guid);
2593*4882a593Smuzhiyun /*
2594*4882a593Smuzhiyun * at this point we are the only ones with the pointer
2595*4882a593Smuzhiyun * to the struct since the kernel thread not created yet
2596*4882a593Smuzhiyun * no need to spinlock this init of tcpStatus or srv_count
2597*4882a593Smuzhiyun */
2598*4882a593Smuzhiyun tcp_ses->tcpStatus = CifsNew;
2599*4882a593Smuzhiyun ++tcp_ses->srv_count;
2600*4882a593Smuzhiyun
2601*4882a593Smuzhiyun if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
2602*4882a593Smuzhiyun volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX)
2603*4882a593Smuzhiyun tcp_ses->echo_interval = volume_info->echo_interval * HZ;
2604*4882a593Smuzhiyun else
2605*4882a593Smuzhiyun tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
2606*4882a593Smuzhiyun if (tcp_ses->rdma) {
2607*4882a593Smuzhiyun #ifndef CONFIG_CIFS_SMB_DIRECT
2608*4882a593Smuzhiyun cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n");
2609*4882a593Smuzhiyun rc = -ENOENT;
2610*4882a593Smuzhiyun goto out_err_crypto_release;
2611*4882a593Smuzhiyun #endif
2612*4882a593Smuzhiyun tcp_ses->smbd_conn = smbd_get_connection(
2613*4882a593Smuzhiyun tcp_ses, (struct sockaddr *)&volume_info->dstaddr);
2614*4882a593Smuzhiyun if (tcp_ses->smbd_conn) {
2615*4882a593Smuzhiyun cifs_dbg(VFS, "RDMA transport established\n");
2616*4882a593Smuzhiyun rc = 0;
2617*4882a593Smuzhiyun goto smbd_connected;
2618*4882a593Smuzhiyun } else {
2619*4882a593Smuzhiyun rc = -ENOENT;
2620*4882a593Smuzhiyun goto out_err_crypto_release;
2621*4882a593Smuzhiyun }
2622*4882a593Smuzhiyun }
2623*4882a593Smuzhiyun rc = ip_connect(tcp_ses);
2624*4882a593Smuzhiyun if (rc < 0) {
2625*4882a593Smuzhiyun cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
2626*4882a593Smuzhiyun goto out_err_crypto_release;
2627*4882a593Smuzhiyun }
2628*4882a593Smuzhiyun smbd_connected:
2629*4882a593Smuzhiyun /*
2630*4882a593Smuzhiyun * since we're in a cifs function already, we know that
2631*4882a593Smuzhiyun * this will succeed. No need for try_module_get().
2632*4882a593Smuzhiyun */
2633*4882a593Smuzhiyun __module_get(THIS_MODULE);
2634*4882a593Smuzhiyun tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
2635*4882a593Smuzhiyun tcp_ses, "cifsd");
2636*4882a593Smuzhiyun if (IS_ERR(tcp_ses->tsk)) {
2637*4882a593Smuzhiyun rc = PTR_ERR(tcp_ses->tsk);
2638*4882a593Smuzhiyun cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
2639*4882a593Smuzhiyun module_put(THIS_MODULE);
2640*4882a593Smuzhiyun goto out_err_crypto_release;
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun tcp_ses->min_offload = volume_info->min_offload;
2643*4882a593Smuzhiyun tcp_ses->tcpStatus = CifsNeedNegotiate;
2644*4882a593Smuzhiyun
2645*4882a593Smuzhiyun if ((volume_info->max_credits < 20) || (volume_info->max_credits > 60000))
2646*4882a593Smuzhiyun tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
2647*4882a593Smuzhiyun else
2648*4882a593Smuzhiyun tcp_ses->max_credits = volume_info->max_credits;
2649*4882a593Smuzhiyun
2650*4882a593Smuzhiyun tcp_ses->nr_targets = 1;
2651*4882a593Smuzhiyun tcp_ses->ignore_signature = volume_info->ignore_signature;
2652*4882a593Smuzhiyun /* thread spawned, put it on the list */
2653*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2654*4882a593Smuzhiyun list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
2655*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2656*4882a593Smuzhiyun
2657*4882a593Smuzhiyun cifs_fscache_get_client_cookie(tcp_ses);
2658*4882a593Smuzhiyun
2659*4882a593Smuzhiyun /* queue echo request delayed work */
2660*4882a593Smuzhiyun queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
2661*4882a593Smuzhiyun
2662*4882a593Smuzhiyun return tcp_ses;
2663*4882a593Smuzhiyun
2664*4882a593Smuzhiyun out_err_crypto_release:
2665*4882a593Smuzhiyun cifs_crypto_secmech_release(tcp_ses);
2666*4882a593Smuzhiyun
2667*4882a593Smuzhiyun put_net(cifs_net_ns(tcp_ses));
2668*4882a593Smuzhiyun
2669*4882a593Smuzhiyun out_err:
2670*4882a593Smuzhiyun if (tcp_ses) {
2671*4882a593Smuzhiyun if (!IS_ERR(tcp_ses->hostname))
2672*4882a593Smuzhiyun kfree(tcp_ses->hostname);
2673*4882a593Smuzhiyun if (tcp_ses->ssocket)
2674*4882a593Smuzhiyun sock_release(tcp_ses->ssocket);
2675*4882a593Smuzhiyun kfree(tcp_ses);
2676*4882a593Smuzhiyun }
2677*4882a593Smuzhiyun return ERR_PTR(rc);
2678*4882a593Smuzhiyun }
2679*4882a593Smuzhiyun
match_session(struct cifs_ses * ses,struct smb_vol * vol)2680*4882a593Smuzhiyun static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
2681*4882a593Smuzhiyun {
2682*4882a593Smuzhiyun if (vol->sectype != Unspecified &&
2683*4882a593Smuzhiyun vol->sectype != ses->sectype)
2684*4882a593Smuzhiyun return 0;
2685*4882a593Smuzhiyun
2686*4882a593Smuzhiyun /*
2687*4882a593Smuzhiyun * If an existing session is limited to less channels than
2688*4882a593Smuzhiyun * requested, it should not be reused
2689*4882a593Smuzhiyun */
2690*4882a593Smuzhiyun if (ses->chan_max < vol->max_channels)
2691*4882a593Smuzhiyun return 0;
2692*4882a593Smuzhiyun
2693*4882a593Smuzhiyun switch (ses->sectype) {
2694*4882a593Smuzhiyun case Kerberos:
2695*4882a593Smuzhiyun if (!uid_eq(vol->cred_uid, ses->cred_uid))
2696*4882a593Smuzhiyun return 0;
2697*4882a593Smuzhiyun break;
2698*4882a593Smuzhiyun default:
2699*4882a593Smuzhiyun /* NULL username means anonymous session */
2700*4882a593Smuzhiyun if (ses->user_name == NULL) {
2701*4882a593Smuzhiyun if (!vol->nullauth)
2702*4882a593Smuzhiyun return 0;
2703*4882a593Smuzhiyun break;
2704*4882a593Smuzhiyun }
2705*4882a593Smuzhiyun
2706*4882a593Smuzhiyun /* anything else takes username/password */
2707*4882a593Smuzhiyun if (strncmp(ses->user_name,
2708*4882a593Smuzhiyun vol->username ? vol->username : "",
2709*4882a593Smuzhiyun CIFS_MAX_USERNAME_LEN))
2710*4882a593Smuzhiyun return 0;
2711*4882a593Smuzhiyun if ((vol->username && strlen(vol->username) != 0) &&
2712*4882a593Smuzhiyun ses->password != NULL &&
2713*4882a593Smuzhiyun strncmp(ses->password,
2714*4882a593Smuzhiyun vol->password ? vol->password : "",
2715*4882a593Smuzhiyun CIFS_MAX_PASSWORD_LEN))
2716*4882a593Smuzhiyun return 0;
2717*4882a593Smuzhiyun }
2718*4882a593Smuzhiyun return 1;
2719*4882a593Smuzhiyun }
2720*4882a593Smuzhiyun
2721*4882a593Smuzhiyun /**
2722*4882a593Smuzhiyun * cifs_setup_ipc - helper to setup the IPC tcon for the session
2723*4882a593Smuzhiyun *
2724*4882a593Smuzhiyun * A new IPC connection is made and stored in the session
2725*4882a593Smuzhiyun * tcon_ipc. The IPC tcon has the same lifetime as the session.
2726*4882a593Smuzhiyun */
2727*4882a593Smuzhiyun static int
cifs_setup_ipc(struct cifs_ses * ses,struct smb_vol * volume_info)2728*4882a593Smuzhiyun cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
2729*4882a593Smuzhiyun {
2730*4882a593Smuzhiyun int rc = 0, xid;
2731*4882a593Smuzhiyun struct cifs_tcon *tcon;
2732*4882a593Smuzhiyun struct nls_table *nls_codepage;
2733*4882a593Smuzhiyun char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
2734*4882a593Smuzhiyun bool seal = false;
2735*4882a593Smuzhiyun struct TCP_Server_Info *server = ses->server;
2736*4882a593Smuzhiyun
2737*4882a593Smuzhiyun /*
2738*4882a593Smuzhiyun * If the mount request that resulted in the creation of the
2739*4882a593Smuzhiyun * session requires encryption, force IPC to be encrypted too.
2740*4882a593Smuzhiyun */
2741*4882a593Smuzhiyun if (volume_info->seal) {
2742*4882a593Smuzhiyun if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
2743*4882a593Smuzhiyun seal = true;
2744*4882a593Smuzhiyun else {
2745*4882a593Smuzhiyun cifs_server_dbg(VFS,
2746*4882a593Smuzhiyun "IPC: server doesn't support encryption\n");
2747*4882a593Smuzhiyun return -EOPNOTSUPP;
2748*4882a593Smuzhiyun }
2749*4882a593Smuzhiyun }
2750*4882a593Smuzhiyun
2751*4882a593Smuzhiyun tcon = tconInfoAlloc();
2752*4882a593Smuzhiyun if (tcon == NULL)
2753*4882a593Smuzhiyun return -ENOMEM;
2754*4882a593Smuzhiyun
2755*4882a593Smuzhiyun scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
2756*4882a593Smuzhiyun
2757*4882a593Smuzhiyun /* cannot fail */
2758*4882a593Smuzhiyun nls_codepage = load_nls_default();
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun xid = get_xid();
2761*4882a593Smuzhiyun tcon->ses = ses;
2762*4882a593Smuzhiyun tcon->ipc = true;
2763*4882a593Smuzhiyun tcon->seal = seal;
2764*4882a593Smuzhiyun rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage);
2765*4882a593Smuzhiyun free_xid(xid);
2766*4882a593Smuzhiyun
2767*4882a593Smuzhiyun if (rc) {
2768*4882a593Smuzhiyun cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
2769*4882a593Smuzhiyun tconInfoFree(tcon);
2770*4882a593Smuzhiyun goto out;
2771*4882a593Smuzhiyun }
2772*4882a593Smuzhiyun
2773*4882a593Smuzhiyun cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
2774*4882a593Smuzhiyun
2775*4882a593Smuzhiyun ses->tcon_ipc = tcon;
2776*4882a593Smuzhiyun out:
2777*4882a593Smuzhiyun unload_nls(nls_codepage);
2778*4882a593Smuzhiyun return rc;
2779*4882a593Smuzhiyun }
2780*4882a593Smuzhiyun
2781*4882a593Smuzhiyun /**
2782*4882a593Smuzhiyun * cifs_free_ipc - helper to release the session IPC tcon
2783*4882a593Smuzhiyun *
2784*4882a593Smuzhiyun * Needs to be called everytime a session is destroyed
2785*4882a593Smuzhiyun */
2786*4882a593Smuzhiyun static int
cifs_free_ipc(struct cifs_ses * ses)2787*4882a593Smuzhiyun cifs_free_ipc(struct cifs_ses *ses)
2788*4882a593Smuzhiyun {
2789*4882a593Smuzhiyun int rc = 0, xid;
2790*4882a593Smuzhiyun struct cifs_tcon *tcon = ses->tcon_ipc;
2791*4882a593Smuzhiyun
2792*4882a593Smuzhiyun if (tcon == NULL)
2793*4882a593Smuzhiyun return 0;
2794*4882a593Smuzhiyun
2795*4882a593Smuzhiyun if (ses->server->ops->tree_disconnect) {
2796*4882a593Smuzhiyun xid = get_xid();
2797*4882a593Smuzhiyun rc = ses->server->ops->tree_disconnect(xid, tcon);
2798*4882a593Smuzhiyun free_xid(xid);
2799*4882a593Smuzhiyun }
2800*4882a593Smuzhiyun
2801*4882a593Smuzhiyun if (rc)
2802*4882a593Smuzhiyun cifs_dbg(FYI, "failed to disconnect IPC tcon (rc=%d)\n", rc);
2803*4882a593Smuzhiyun
2804*4882a593Smuzhiyun tconInfoFree(tcon);
2805*4882a593Smuzhiyun ses->tcon_ipc = NULL;
2806*4882a593Smuzhiyun return rc;
2807*4882a593Smuzhiyun }
2808*4882a593Smuzhiyun
2809*4882a593Smuzhiyun static struct cifs_ses *
cifs_find_smb_ses(struct TCP_Server_Info * server,struct smb_vol * vol)2810*4882a593Smuzhiyun cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2811*4882a593Smuzhiyun {
2812*4882a593Smuzhiyun struct cifs_ses *ses;
2813*4882a593Smuzhiyun
2814*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2815*4882a593Smuzhiyun list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
2816*4882a593Smuzhiyun if (ses->status == CifsExiting)
2817*4882a593Smuzhiyun continue;
2818*4882a593Smuzhiyun if (!match_session(ses, vol))
2819*4882a593Smuzhiyun continue;
2820*4882a593Smuzhiyun ++ses->ses_count;
2821*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2822*4882a593Smuzhiyun return ses;
2823*4882a593Smuzhiyun }
2824*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2825*4882a593Smuzhiyun return NULL;
2826*4882a593Smuzhiyun }
2827*4882a593Smuzhiyun
cifs_put_smb_ses(struct cifs_ses * ses)2828*4882a593Smuzhiyun void cifs_put_smb_ses(struct cifs_ses *ses)
2829*4882a593Smuzhiyun {
2830*4882a593Smuzhiyun unsigned int rc, xid;
2831*4882a593Smuzhiyun struct TCP_Server_Info *server = ses->server;
2832*4882a593Smuzhiyun
2833*4882a593Smuzhiyun cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
2834*4882a593Smuzhiyun
2835*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2836*4882a593Smuzhiyun if (ses->status == CifsExiting) {
2837*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2838*4882a593Smuzhiyun return;
2839*4882a593Smuzhiyun }
2840*4882a593Smuzhiyun if (--ses->ses_count > 0) {
2841*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2842*4882a593Smuzhiyun return;
2843*4882a593Smuzhiyun }
2844*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2845*4882a593Smuzhiyun
2846*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
2847*4882a593Smuzhiyun if (ses->status == CifsGood)
2848*4882a593Smuzhiyun ses->status = CifsExiting;
2849*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
2850*4882a593Smuzhiyun
2851*4882a593Smuzhiyun cifs_free_ipc(ses);
2852*4882a593Smuzhiyun
2853*4882a593Smuzhiyun if (ses->status == CifsExiting && server->ops->logoff) {
2854*4882a593Smuzhiyun xid = get_xid();
2855*4882a593Smuzhiyun rc = server->ops->logoff(xid, ses);
2856*4882a593Smuzhiyun if (rc)
2857*4882a593Smuzhiyun cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
2858*4882a593Smuzhiyun __func__, rc);
2859*4882a593Smuzhiyun _free_xid(xid);
2860*4882a593Smuzhiyun }
2861*4882a593Smuzhiyun
2862*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
2863*4882a593Smuzhiyun list_del_init(&ses->smb_ses_list);
2864*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
2865*4882a593Smuzhiyun
2866*4882a593Smuzhiyun /* close any extra channels */
2867*4882a593Smuzhiyun if (ses->chan_count > 1) {
2868*4882a593Smuzhiyun int i;
2869*4882a593Smuzhiyun
2870*4882a593Smuzhiyun for (i = 1; i < ses->chan_count; i++)
2871*4882a593Smuzhiyun cifs_put_tcp_session(ses->chans[i].server, 0);
2872*4882a593Smuzhiyun }
2873*4882a593Smuzhiyun
2874*4882a593Smuzhiyun sesInfoFree(ses);
2875*4882a593Smuzhiyun cifs_put_tcp_session(server, 0);
2876*4882a593Smuzhiyun }
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun #ifdef CONFIG_KEYS
2879*4882a593Smuzhiyun
2880*4882a593Smuzhiyun /* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
2881*4882a593Smuzhiyun #define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
2882*4882a593Smuzhiyun
2883*4882a593Smuzhiyun /* Populate username and pw fields from keyring if possible */
2884*4882a593Smuzhiyun static int
cifs_set_cifscreds(struct smb_vol * vol,struct cifs_ses * ses)2885*4882a593Smuzhiyun cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
2886*4882a593Smuzhiyun {
2887*4882a593Smuzhiyun int rc = 0;
2888*4882a593Smuzhiyun int is_domain = 0;
2889*4882a593Smuzhiyun const char *delim, *payload;
2890*4882a593Smuzhiyun char *desc;
2891*4882a593Smuzhiyun ssize_t len;
2892*4882a593Smuzhiyun struct key *key;
2893*4882a593Smuzhiyun struct TCP_Server_Info *server = ses->server;
2894*4882a593Smuzhiyun struct sockaddr_in *sa;
2895*4882a593Smuzhiyun struct sockaddr_in6 *sa6;
2896*4882a593Smuzhiyun const struct user_key_payload *upayload;
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
2899*4882a593Smuzhiyun if (!desc)
2900*4882a593Smuzhiyun return -ENOMEM;
2901*4882a593Smuzhiyun
2902*4882a593Smuzhiyun /* try to find an address key first */
2903*4882a593Smuzhiyun switch (server->dstaddr.ss_family) {
2904*4882a593Smuzhiyun case AF_INET:
2905*4882a593Smuzhiyun sa = (struct sockaddr_in *)&server->dstaddr;
2906*4882a593Smuzhiyun sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
2907*4882a593Smuzhiyun break;
2908*4882a593Smuzhiyun case AF_INET6:
2909*4882a593Smuzhiyun sa6 = (struct sockaddr_in6 *)&server->dstaddr;
2910*4882a593Smuzhiyun sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
2911*4882a593Smuzhiyun break;
2912*4882a593Smuzhiyun default:
2913*4882a593Smuzhiyun cifs_dbg(FYI, "Bad ss_family (%hu)\n",
2914*4882a593Smuzhiyun server->dstaddr.ss_family);
2915*4882a593Smuzhiyun rc = -EINVAL;
2916*4882a593Smuzhiyun goto out_err;
2917*4882a593Smuzhiyun }
2918*4882a593Smuzhiyun
2919*4882a593Smuzhiyun cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
2920*4882a593Smuzhiyun key = request_key(&key_type_logon, desc, "");
2921*4882a593Smuzhiyun if (IS_ERR(key)) {
2922*4882a593Smuzhiyun if (!ses->domainName) {
2923*4882a593Smuzhiyun cifs_dbg(FYI, "domainName is NULL\n");
2924*4882a593Smuzhiyun rc = PTR_ERR(key);
2925*4882a593Smuzhiyun goto out_err;
2926*4882a593Smuzhiyun }
2927*4882a593Smuzhiyun
2928*4882a593Smuzhiyun /* didn't work, try to find a domain key */
2929*4882a593Smuzhiyun sprintf(desc, "cifs:d:%s", ses->domainName);
2930*4882a593Smuzhiyun cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
2931*4882a593Smuzhiyun key = request_key(&key_type_logon, desc, "");
2932*4882a593Smuzhiyun if (IS_ERR(key)) {
2933*4882a593Smuzhiyun rc = PTR_ERR(key);
2934*4882a593Smuzhiyun goto out_err;
2935*4882a593Smuzhiyun }
2936*4882a593Smuzhiyun is_domain = 1;
2937*4882a593Smuzhiyun }
2938*4882a593Smuzhiyun
2939*4882a593Smuzhiyun down_read(&key->sem);
2940*4882a593Smuzhiyun upayload = user_key_payload_locked(key);
2941*4882a593Smuzhiyun if (IS_ERR_OR_NULL(upayload)) {
2942*4882a593Smuzhiyun rc = upayload ? PTR_ERR(upayload) : -EINVAL;
2943*4882a593Smuzhiyun goto out_key_put;
2944*4882a593Smuzhiyun }
2945*4882a593Smuzhiyun
2946*4882a593Smuzhiyun /* find first : in payload */
2947*4882a593Smuzhiyun payload = upayload->data;
2948*4882a593Smuzhiyun delim = strnchr(payload, upayload->datalen, ':');
2949*4882a593Smuzhiyun cifs_dbg(FYI, "payload=%s\n", payload);
2950*4882a593Smuzhiyun if (!delim) {
2951*4882a593Smuzhiyun cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
2952*4882a593Smuzhiyun upayload->datalen);
2953*4882a593Smuzhiyun rc = -EINVAL;
2954*4882a593Smuzhiyun goto out_key_put;
2955*4882a593Smuzhiyun }
2956*4882a593Smuzhiyun
2957*4882a593Smuzhiyun len = delim - payload;
2958*4882a593Smuzhiyun if (len > CIFS_MAX_USERNAME_LEN || len <= 0) {
2959*4882a593Smuzhiyun cifs_dbg(FYI, "Bad value from username search (len=%zd)\n",
2960*4882a593Smuzhiyun len);
2961*4882a593Smuzhiyun rc = -EINVAL;
2962*4882a593Smuzhiyun goto out_key_put;
2963*4882a593Smuzhiyun }
2964*4882a593Smuzhiyun
2965*4882a593Smuzhiyun vol->username = kstrndup(payload, len, GFP_KERNEL);
2966*4882a593Smuzhiyun if (!vol->username) {
2967*4882a593Smuzhiyun cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n",
2968*4882a593Smuzhiyun len);
2969*4882a593Smuzhiyun rc = -ENOMEM;
2970*4882a593Smuzhiyun goto out_key_put;
2971*4882a593Smuzhiyun }
2972*4882a593Smuzhiyun cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username);
2973*4882a593Smuzhiyun
2974*4882a593Smuzhiyun len = key->datalen - (len + 1);
2975*4882a593Smuzhiyun if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) {
2976*4882a593Smuzhiyun cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len);
2977*4882a593Smuzhiyun rc = -EINVAL;
2978*4882a593Smuzhiyun kfree(vol->username);
2979*4882a593Smuzhiyun vol->username = NULL;
2980*4882a593Smuzhiyun goto out_key_put;
2981*4882a593Smuzhiyun }
2982*4882a593Smuzhiyun
2983*4882a593Smuzhiyun ++delim;
2984*4882a593Smuzhiyun vol->password = kstrndup(delim, len, GFP_KERNEL);
2985*4882a593Smuzhiyun if (!vol->password) {
2986*4882a593Smuzhiyun cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
2987*4882a593Smuzhiyun len);
2988*4882a593Smuzhiyun rc = -ENOMEM;
2989*4882a593Smuzhiyun kfree(vol->username);
2990*4882a593Smuzhiyun vol->username = NULL;
2991*4882a593Smuzhiyun goto out_key_put;
2992*4882a593Smuzhiyun }
2993*4882a593Smuzhiyun
2994*4882a593Smuzhiyun /*
2995*4882a593Smuzhiyun * If we have a domain key then we must set the domainName in the
2996*4882a593Smuzhiyun * for the request.
2997*4882a593Smuzhiyun */
2998*4882a593Smuzhiyun if (is_domain && ses->domainName) {
2999*4882a593Smuzhiyun vol->domainname = kstrndup(ses->domainName,
3000*4882a593Smuzhiyun strlen(ses->domainName),
3001*4882a593Smuzhiyun GFP_KERNEL);
3002*4882a593Smuzhiyun if (!vol->domainname) {
3003*4882a593Smuzhiyun cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
3004*4882a593Smuzhiyun len);
3005*4882a593Smuzhiyun rc = -ENOMEM;
3006*4882a593Smuzhiyun kfree(vol->username);
3007*4882a593Smuzhiyun vol->username = NULL;
3008*4882a593Smuzhiyun kfree_sensitive(vol->password);
3009*4882a593Smuzhiyun vol->password = NULL;
3010*4882a593Smuzhiyun goto out_key_put;
3011*4882a593Smuzhiyun }
3012*4882a593Smuzhiyun }
3013*4882a593Smuzhiyun
3014*4882a593Smuzhiyun out_key_put:
3015*4882a593Smuzhiyun up_read(&key->sem);
3016*4882a593Smuzhiyun key_put(key);
3017*4882a593Smuzhiyun out_err:
3018*4882a593Smuzhiyun kfree(desc);
3019*4882a593Smuzhiyun cifs_dbg(FYI, "%s: returning %d\n", __func__, rc);
3020*4882a593Smuzhiyun return rc;
3021*4882a593Smuzhiyun }
3022*4882a593Smuzhiyun #else /* ! CONFIG_KEYS */
3023*4882a593Smuzhiyun static inline int
cifs_set_cifscreds(struct smb_vol * vol,struct cifs_ses * ses)3024*4882a593Smuzhiyun cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
3025*4882a593Smuzhiyun struct cifs_ses *ses __attribute__((unused)))
3026*4882a593Smuzhiyun {
3027*4882a593Smuzhiyun return -ENOSYS;
3028*4882a593Smuzhiyun }
3029*4882a593Smuzhiyun #endif /* CONFIG_KEYS */
3030*4882a593Smuzhiyun
3031*4882a593Smuzhiyun /**
3032*4882a593Smuzhiyun * cifs_get_smb_ses - get a session matching @volume_info data from @server
3033*4882a593Smuzhiyun *
3034*4882a593Smuzhiyun * This function assumes it is being called from cifs_mount() where we
3035*4882a593Smuzhiyun * already got a server reference (server refcount +1). See
3036*4882a593Smuzhiyun * cifs_get_tcon() for refcount explanations.
3037*4882a593Smuzhiyun */
3038*4882a593Smuzhiyun struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info * server,struct smb_vol * volume_info)3039*4882a593Smuzhiyun cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
3040*4882a593Smuzhiyun {
3041*4882a593Smuzhiyun int rc = -ENOMEM;
3042*4882a593Smuzhiyun unsigned int xid;
3043*4882a593Smuzhiyun struct cifs_ses *ses;
3044*4882a593Smuzhiyun struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3045*4882a593Smuzhiyun struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
3046*4882a593Smuzhiyun
3047*4882a593Smuzhiyun xid = get_xid();
3048*4882a593Smuzhiyun
3049*4882a593Smuzhiyun ses = cifs_find_smb_ses(server, volume_info);
3050*4882a593Smuzhiyun if (ses) {
3051*4882a593Smuzhiyun cifs_dbg(FYI, "Existing smb sess found (status=%d)\n",
3052*4882a593Smuzhiyun ses->status);
3053*4882a593Smuzhiyun
3054*4882a593Smuzhiyun mutex_lock(&ses->session_mutex);
3055*4882a593Smuzhiyun rc = cifs_negotiate_protocol(xid, ses);
3056*4882a593Smuzhiyun if (rc) {
3057*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
3058*4882a593Smuzhiyun /* problem -- put our ses reference */
3059*4882a593Smuzhiyun cifs_put_smb_ses(ses);
3060*4882a593Smuzhiyun free_xid(xid);
3061*4882a593Smuzhiyun return ERR_PTR(rc);
3062*4882a593Smuzhiyun }
3063*4882a593Smuzhiyun if (ses->need_reconnect) {
3064*4882a593Smuzhiyun cifs_dbg(FYI, "Session needs reconnect\n");
3065*4882a593Smuzhiyun rc = cifs_setup_session(xid, ses,
3066*4882a593Smuzhiyun volume_info->local_nls);
3067*4882a593Smuzhiyun if (rc) {
3068*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
3069*4882a593Smuzhiyun /* problem -- put our reference */
3070*4882a593Smuzhiyun cifs_put_smb_ses(ses);
3071*4882a593Smuzhiyun free_xid(xid);
3072*4882a593Smuzhiyun return ERR_PTR(rc);
3073*4882a593Smuzhiyun }
3074*4882a593Smuzhiyun }
3075*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
3076*4882a593Smuzhiyun
3077*4882a593Smuzhiyun /* existing SMB ses has a server reference already */
3078*4882a593Smuzhiyun cifs_put_tcp_session(server, 0);
3079*4882a593Smuzhiyun free_xid(xid);
3080*4882a593Smuzhiyun return ses;
3081*4882a593Smuzhiyun }
3082*4882a593Smuzhiyun
3083*4882a593Smuzhiyun cifs_dbg(FYI, "Existing smb sess not found\n");
3084*4882a593Smuzhiyun ses = sesInfoAlloc();
3085*4882a593Smuzhiyun if (ses == NULL)
3086*4882a593Smuzhiyun goto get_ses_fail;
3087*4882a593Smuzhiyun
3088*4882a593Smuzhiyun /* new SMB session uses our server ref */
3089*4882a593Smuzhiyun ses->server = server;
3090*4882a593Smuzhiyun if (server->dstaddr.ss_family == AF_INET6)
3091*4882a593Smuzhiyun sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
3092*4882a593Smuzhiyun else
3093*4882a593Smuzhiyun sprintf(ses->serverName, "%pI4", &addr->sin_addr);
3094*4882a593Smuzhiyun
3095*4882a593Smuzhiyun if (volume_info->username) {
3096*4882a593Smuzhiyun ses->user_name = kstrdup(volume_info->username, GFP_KERNEL);
3097*4882a593Smuzhiyun if (!ses->user_name)
3098*4882a593Smuzhiyun goto get_ses_fail;
3099*4882a593Smuzhiyun }
3100*4882a593Smuzhiyun
3101*4882a593Smuzhiyun /* volume_info->password freed at unmount */
3102*4882a593Smuzhiyun if (volume_info->password) {
3103*4882a593Smuzhiyun ses->password = kstrdup(volume_info->password, GFP_KERNEL);
3104*4882a593Smuzhiyun if (!ses->password)
3105*4882a593Smuzhiyun goto get_ses_fail;
3106*4882a593Smuzhiyun }
3107*4882a593Smuzhiyun if (volume_info->domainname) {
3108*4882a593Smuzhiyun ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL);
3109*4882a593Smuzhiyun if (!ses->domainName)
3110*4882a593Smuzhiyun goto get_ses_fail;
3111*4882a593Smuzhiyun }
3112*4882a593Smuzhiyun if (volume_info->domainauto)
3113*4882a593Smuzhiyun ses->domainAuto = volume_info->domainauto;
3114*4882a593Smuzhiyun ses->cred_uid = volume_info->cred_uid;
3115*4882a593Smuzhiyun ses->linux_uid = volume_info->linux_uid;
3116*4882a593Smuzhiyun
3117*4882a593Smuzhiyun ses->sectype = volume_info->sectype;
3118*4882a593Smuzhiyun ses->sign = volume_info->sign;
3119*4882a593Smuzhiyun mutex_lock(&ses->session_mutex);
3120*4882a593Smuzhiyun
3121*4882a593Smuzhiyun /* add server as first channel */
3122*4882a593Smuzhiyun ses->chans[0].server = server;
3123*4882a593Smuzhiyun ses->chan_count = 1;
3124*4882a593Smuzhiyun ses->chan_max = volume_info->multichannel ? volume_info->max_channels:1;
3125*4882a593Smuzhiyun
3126*4882a593Smuzhiyun rc = cifs_negotiate_protocol(xid, ses);
3127*4882a593Smuzhiyun if (!rc)
3128*4882a593Smuzhiyun rc = cifs_setup_session(xid, ses, volume_info->local_nls);
3129*4882a593Smuzhiyun
3130*4882a593Smuzhiyun /* each channel uses a different signing key */
3131*4882a593Smuzhiyun memcpy(ses->chans[0].signkey, ses->smb3signingkey,
3132*4882a593Smuzhiyun sizeof(ses->smb3signingkey));
3133*4882a593Smuzhiyun
3134*4882a593Smuzhiyun mutex_unlock(&ses->session_mutex);
3135*4882a593Smuzhiyun if (rc)
3136*4882a593Smuzhiyun goto get_ses_fail;
3137*4882a593Smuzhiyun
3138*4882a593Smuzhiyun /* success, put it on the list and add it as first channel */
3139*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
3140*4882a593Smuzhiyun list_add(&ses->smb_ses_list, &server->smb_ses_list);
3141*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3142*4882a593Smuzhiyun
3143*4882a593Smuzhiyun free_xid(xid);
3144*4882a593Smuzhiyun
3145*4882a593Smuzhiyun cifs_setup_ipc(ses, volume_info);
3146*4882a593Smuzhiyun
3147*4882a593Smuzhiyun return ses;
3148*4882a593Smuzhiyun
3149*4882a593Smuzhiyun get_ses_fail:
3150*4882a593Smuzhiyun sesInfoFree(ses);
3151*4882a593Smuzhiyun free_xid(xid);
3152*4882a593Smuzhiyun return ERR_PTR(rc);
3153*4882a593Smuzhiyun }
3154*4882a593Smuzhiyun
match_tcon(struct cifs_tcon * tcon,struct smb_vol * volume_info)3155*4882a593Smuzhiyun static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
3156*4882a593Smuzhiyun {
3157*4882a593Smuzhiyun if (tcon->tidStatus == CifsExiting)
3158*4882a593Smuzhiyun return 0;
3159*4882a593Smuzhiyun if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
3160*4882a593Smuzhiyun return 0;
3161*4882a593Smuzhiyun if (tcon->seal != volume_info->seal)
3162*4882a593Smuzhiyun return 0;
3163*4882a593Smuzhiyun if (tcon->snapshot_time != volume_info->snapshot_time)
3164*4882a593Smuzhiyun return 0;
3165*4882a593Smuzhiyun if (tcon->handle_timeout != volume_info->handle_timeout)
3166*4882a593Smuzhiyun return 0;
3167*4882a593Smuzhiyun if (tcon->no_lease != volume_info->no_lease)
3168*4882a593Smuzhiyun return 0;
3169*4882a593Smuzhiyun if (tcon->nodelete != volume_info->nodelete)
3170*4882a593Smuzhiyun return 0;
3171*4882a593Smuzhiyun return 1;
3172*4882a593Smuzhiyun }
3173*4882a593Smuzhiyun
3174*4882a593Smuzhiyun static struct cifs_tcon *
cifs_find_tcon(struct cifs_ses * ses,struct smb_vol * volume_info)3175*4882a593Smuzhiyun cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
3176*4882a593Smuzhiyun {
3177*4882a593Smuzhiyun struct list_head *tmp;
3178*4882a593Smuzhiyun struct cifs_tcon *tcon;
3179*4882a593Smuzhiyun
3180*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
3181*4882a593Smuzhiyun list_for_each(tmp, &ses->tcon_list) {
3182*4882a593Smuzhiyun tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
3183*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
3184*4882a593Smuzhiyun if (tcon->dfs_path)
3185*4882a593Smuzhiyun continue;
3186*4882a593Smuzhiyun #endif
3187*4882a593Smuzhiyun if (!match_tcon(tcon, volume_info))
3188*4882a593Smuzhiyun continue;
3189*4882a593Smuzhiyun ++tcon->tc_count;
3190*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3191*4882a593Smuzhiyun return tcon;
3192*4882a593Smuzhiyun }
3193*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3194*4882a593Smuzhiyun return NULL;
3195*4882a593Smuzhiyun }
3196*4882a593Smuzhiyun
3197*4882a593Smuzhiyun void
cifs_put_tcon(struct cifs_tcon * tcon)3198*4882a593Smuzhiyun cifs_put_tcon(struct cifs_tcon *tcon)
3199*4882a593Smuzhiyun {
3200*4882a593Smuzhiyun unsigned int xid;
3201*4882a593Smuzhiyun struct cifs_ses *ses;
3202*4882a593Smuzhiyun
3203*4882a593Smuzhiyun /*
3204*4882a593Smuzhiyun * IPC tcon share the lifetime of their session and are
3205*4882a593Smuzhiyun * destroyed in the session put function
3206*4882a593Smuzhiyun */
3207*4882a593Smuzhiyun if (tcon == NULL || tcon->ipc)
3208*4882a593Smuzhiyun return;
3209*4882a593Smuzhiyun
3210*4882a593Smuzhiyun ses = tcon->ses;
3211*4882a593Smuzhiyun cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
3212*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
3213*4882a593Smuzhiyun if (--tcon->tc_count > 0) {
3214*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3215*4882a593Smuzhiyun return;
3216*4882a593Smuzhiyun }
3217*4882a593Smuzhiyun
3218*4882a593Smuzhiyun list_del_init(&tcon->tcon_list);
3219*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3220*4882a593Smuzhiyun
3221*4882a593Smuzhiyun xid = get_xid();
3222*4882a593Smuzhiyun if (ses->server->ops->tree_disconnect)
3223*4882a593Smuzhiyun ses->server->ops->tree_disconnect(xid, tcon);
3224*4882a593Smuzhiyun _free_xid(xid);
3225*4882a593Smuzhiyun
3226*4882a593Smuzhiyun cifs_fscache_release_super_cookie(tcon);
3227*4882a593Smuzhiyun tconInfoFree(tcon);
3228*4882a593Smuzhiyun cifs_put_smb_ses(ses);
3229*4882a593Smuzhiyun }
3230*4882a593Smuzhiyun
3231*4882a593Smuzhiyun /**
3232*4882a593Smuzhiyun * cifs_get_tcon - get a tcon matching @volume_info data from @ses
3233*4882a593Smuzhiyun *
3234*4882a593Smuzhiyun * - tcon refcount is the number of mount points using the tcon.
3235*4882a593Smuzhiyun * - ses refcount is the number of tcon using the session.
3236*4882a593Smuzhiyun *
3237*4882a593Smuzhiyun * 1. This function assumes it is being called from cifs_mount() where
3238*4882a593Smuzhiyun * we already got a session reference (ses refcount +1).
3239*4882a593Smuzhiyun *
3240*4882a593Smuzhiyun * 2. Since we're in the context of adding a mount point, the end
3241*4882a593Smuzhiyun * result should be either:
3242*4882a593Smuzhiyun *
3243*4882a593Smuzhiyun * a) a new tcon already allocated with refcount=1 (1 mount point) and
3244*4882a593Smuzhiyun * its session refcount incremented (1 new tcon). This +1 was
3245*4882a593Smuzhiyun * already done in (1).
3246*4882a593Smuzhiyun *
3247*4882a593Smuzhiyun * b) an existing tcon with refcount+1 (add a mount point to it) and
3248*4882a593Smuzhiyun * identical ses refcount (no new tcon). Because of (1) we need to
3249*4882a593Smuzhiyun * decrement the ses refcount.
3250*4882a593Smuzhiyun */
3251*4882a593Smuzhiyun static struct cifs_tcon *
cifs_get_tcon(struct cifs_ses * ses,struct smb_vol * volume_info)3252*4882a593Smuzhiyun cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
3253*4882a593Smuzhiyun {
3254*4882a593Smuzhiyun int rc, xid;
3255*4882a593Smuzhiyun struct cifs_tcon *tcon;
3256*4882a593Smuzhiyun
3257*4882a593Smuzhiyun tcon = cifs_find_tcon(ses, volume_info);
3258*4882a593Smuzhiyun if (tcon) {
3259*4882a593Smuzhiyun /*
3260*4882a593Smuzhiyun * tcon has refcount already incremented but we need to
3261*4882a593Smuzhiyun * decrement extra ses reference gotten by caller (case b)
3262*4882a593Smuzhiyun */
3263*4882a593Smuzhiyun cifs_dbg(FYI, "Found match on UNC path\n");
3264*4882a593Smuzhiyun cifs_put_smb_ses(ses);
3265*4882a593Smuzhiyun return tcon;
3266*4882a593Smuzhiyun }
3267*4882a593Smuzhiyun
3268*4882a593Smuzhiyun if (!ses->server->ops->tree_connect) {
3269*4882a593Smuzhiyun rc = -ENOSYS;
3270*4882a593Smuzhiyun goto out_fail;
3271*4882a593Smuzhiyun }
3272*4882a593Smuzhiyun
3273*4882a593Smuzhiyun tcon = tconInfoAlloc();
3274*4882a593Smuzhiyun if (tcon == NULL) {
3275*4882a593Smuzhiyun rc = -ENOMEM;
3276*4882a593Smuzhiyun goto out_fail;
3277*4882a593Smuzhiyun }
3278*4882a593Smuzhiyun
3279*4882a593Smuzhiyun if (volume_info->snapshot_time) {
3280*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3281*4882a593Smuzhiyun cifs_dbg(VFS,
3282*4882a593Smuzhiyun "Use SMB2 or later for snapshot mount option\n");
3283*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3284*4882a593Smuzhiyun goto out_fail;
3285*4882a593Smuzhiyun } else
3286*4882a593Smuzhiyun tcon->snapshot_time = volume_info->snapshot_time;
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun
3289*4882a593Smuzhiyun if (volume_info->handle_timeout) {
3290*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3291*4882a593Smuzhiyun cifs_dbg(VFS,
3292*4882a593Smuzhiyun "Use SMB2.1 or later for handle timeout option\n");
3293*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3294*4882a593Smuzhiyun goto out_fail;
3295*4882a593Smuzhiyun } else
3296*4882a593Smuzhiyun tcon->handle_timeout = volume_info->handle_timeout;
3297*4882a593Smuzhiyun }
3298*4882a593Smuzhiyun
3299*4882a593Smuzhiyun tcon->ses = ses;
3300*4882a593Smuzhiyun if (volume_info->password) {
3301*4882a593Smuzhiyun tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
3302*4882a593Smuzhiyun if (!tcon->password) {
3303*4882a593Smuzhiyun rc = -ENOMEM;
3304*4882a593Smuzhiyun goto out_fail;
3305*4882a593Smuzhiyun }
3306*4882a593Smuzhiyun }
3307*4882a593Smuzhiyun
3308*4882a593Smuzhiyun if (volume_info->seal) {
3309*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3310*4882a593Smuzhiyun cifs_dbg(VFS,
3311*4882a593Smuzhiyun "SMB3 or later required for encryption\n");
3312*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3313*4882a593Smuzhiyun goto out_fail;
3314*4882a593Smuzhiyun } else if (tcon->ses->server->capabilities &
3315*4882a593Smuzhiyun SMB2_GLOBAL_CAP_ENCRYPTION)
3316*4882a593Smuzhiyun tcon->seal = true;
3317*4882a593Smuzhiyun else {
3318*4882a593Smuzhiyun cifs_dbg(VFS, "Encryption is not supported on share\n");
3319*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3320*4882a593Smuzhiyun goto out_fail;
3321*4882a593Smuzhiyun }
3322*4882a593Smuzhiyun }
3323*4882a593Smuzhiyun
3324*4882a593Smuzhiyun if (volume_info->linux_ext) {
3325*4882a593Smuzhiyun if (ses->server->posix_ext_supported) {
3326*4882a593Smuzhiyun tcon->posix_extensions = true;
3327*4882a593Smuzhiyun pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
3328*4882a593Smuzhiyun } else {
3329*4882a593Smuzhiyun cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
3330*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3331*4882a593Smuzhiyun goto out_fail;
3332*4882a593Smuzhiyun }
3333*4882a593Smuzhiyun }
3334*4882a593Smuzhiyun
3335*4882a593Smuzhiyun /*
3336*4882a593Smuzhiyun * BB Do we need to wrap session_mutex around this TCon call and Unix
3337*4882a593Smuzhiyun * SetFS as we do on SessSetup and reconnect?
3338*4882a593Smuzhiyun */
3339*4882a593Smuzhiyun xid = get_xid();
3340*4882a593Smuzhiyun rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon,
3341*4882a593Smuzhiyun volume_info->local_nls);
3342*4882a593Smuzhiyun free_xid(xid);
3343*4882a593Smuzhiyun cifs_dbg(FYI, "Tcon rc = %d\n", rc);
3344*4882a593Smuzhiyun if (rc)
3345*4882a593Smuzhiyun goto out_fail;
3346*4882a593Smuzhiyun
3347*4882a593Smuzhiyun tcon->use_persistent = false;
3348*4882a593Smuzhiyun /* check if SMB2 or later, CIFS does not support persistent handles */
3349*4882a593Smuzhiyun if (volume_info->persistent) {
3350*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3351*4882a593Smuzhiyun cifs_dbg(VFS,
3352*4882a593Smuzhiyun "SMB3 or later required for persistent handles\n");
3353*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3354*4882a593Smuzhiyun goto out_fail;
3355*4882a593Smuzhiyun } else if (ses->server->capabilities &
3356*4882a593Smuzhiyun SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
3357*4882a593Smuzhiyun tcon->use_persistent = true;
3358*4882a593Smuzhiyun else /* persistent handles requested but not supported */ {
3359*4882a593Smuzhiyun cifs_dbg(VFS,
3360*4882a593Smuzhiyun "Persistent handles not supported on share\n");
3361*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3362*4882a593Smuzhiyun goto out_fail;
3363*4882a593Smuzhiyun }
3364*4882a593Smuzhiyun } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
3365*4882a593Smuzhiyun && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
3366*4882a593Smuzhiyun && (volume_info->nopersistent == false)) {
3367*4882a593Smuzhiyun cifs_dbg(FYI, "enabling persistent handles\n");
3368*4882a593Smuzhiyun tcon->use_persistent = true;
3369*4882a593Smuzhiyun } else if (volume_info->resilient) {
3370*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3371*4882a593Smuzhiyun cifs_dbg(VFS,
3372*4882a593Smuzhiyun "SMB2.1 or later required for resilient handles\n");
3373*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3374*4882a593Smuzhiyun goto out_fail;
3375*4882a593Smuzhiyun }
3376*4882a593Smuzhiyun tcon->use_resilient = true;
3377*4882a593Smuzhiyun }
3378*4882a593Smuzhiyun
3379*4882a593Smuzhiyun /* If the user really knows what they are doing they can override */
3380*4882a593Smuzhiyun if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
3381*4882a593Smuzhiyun if (volume_info->cache_ro)
3382*4882a593Smuzhiyun cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n");
3383*4882a593Smuzhiyun else if (volume_info->cache_rw)
3384*4882a593Smuzhiyun cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n");
3385*4882a593Smuzhiyun }
3386*4882a593Smuzhiyun
3387*4882a593Smuzhiyun if (volume_info->no_lease) {
3388*4882a593Smuzhiyun if (ses->server->vals->protocol_id == 0) {
3389*4882a593Smuzhiyun cifs_dbg(VFS,
3390*4882a593Smuzhiyun "SMB2 or later required for nolease option\n");
3391*4882a593Smuzhiyun rc = -EOPNOTSUPP;
3392*4882a593Smuzhiyun goto out_fail;
3393*4882a593Smuzhiyun } else
3394*4882a593Smuzhiyun tcon->no_lease = volume_info->no_lease;
3395*4882a593Smuzhiyun }
3396*4882a593Smuzhiyun
3397*4882a593Smuzhiyun /*
3398*4882a593Smuzhiyun * We can have only one retry value for a connection to a share so for
3399*4882a593Smuzhiyun * resources mounted more than once to the same server share the last
3400*4882a593Smuzhiyun * value passed in for the retry flag is used.
3401*4882a593Smuzhiyun */
3402*4882a593Smuzhiyun tcon->retry = volume_info->retry;
3403*4882a593Smuzhiyun tcon->nocase = volume_info->nocase;
3404*4882a593Smuzhiyun if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
3405*4882a593Smuzhiyun tcon->nohandlecache = volume_info->nohandlecache;
3406*4882a593Smuzhiyun else
3407*4882a593Smuzhiyun tcon->nohandlecache = 1;
3408*4882a593Smuzhiyun tcon->nodelete = volume_info->nodelete;
3409*4882a593Smuzhiyun tcon->local_lease = volume_info->local_lease;
3410*4882a593Smuzhiyun INIT_LIST_HEAD(&tcon->pending_opens);
3411*4882a593Smuzhiyun
3412*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
3413*4882a593Smuzhiyun list_add(&tcon->tcon_list, &ses->tcon_list);
3414*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3415*4882a593Smuzhiyun
3416*4882a593Smuzhiyun cifs_fscache_get_super_cookie(tcon);
3417*4882a593Smuzhiyun
3418*4882a593Smuzhiyun return tcon;
3419*4882a593Smuzhiyun
3420*4882a593Smuzhiyun out_fail:
3421*4882a593Smuzhiyun tconInfoFree(tcon);
3422*4882a593Smuzhiyun return ERR_PTR(rc);
3423*4882a593Smuzhiyun }
3424*4882a593Smuzhiyun
3425*4882a593Smuzhiyun void
cifs_put_tlink(struct tcon_link * tlink)3426*4882a593Smuzhiyun cifs_put_tlink(struct tcon_link *tlink)
3427*4882a593Smuzhiyun {
3428*4882a593Smuzhiyun if (!tlink || IS_ERR(tlink))
3429*4882a593Smuzhiyun return;
3430*4882a593Smuzhiyun
3431*4882a593Smuzhiyun if (!atomic_dec_and_test(&tlink->tl_count) ||
3432*4882a593Smuzhiyun test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
3433*4882a593Smuzhiyun tlink->tl_time = jiffies;
3434*4882a593Smuzhiyun return;
3435*4882a593Smuzhiyun }
3436*4882a593Smuzhiyun
3437*4882a593Smuzhiyun if (!IS_ERR(tlink_tcon(tlink)))
3438*4882a593Smuzhiyun cifs_put_tcon(tlink_tcon(tlink));
3439*4882a593Smuzhiyun kfree(tlink);
3440*4882a593Smuzhiyun return;
3441*4882a593Smuzhiyun }
3442*4882a593Smuzhiyun
3443*4882a593Smuzhiyun static int
compare_mount_options(struct super_block * sb,struct cifs_mnt_data * mnt_data)3444*4882a593Smuzhiyun compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
3445*4882a593Smuzhiyun {
3446*4882a593Smuzhiyun struct cifs_sb_info *old = CIFS_SB(sb);
3447*4882a593Smuzhiyun struct cifs_sb_info *new = mnt_data->cifs_sb;
3448*4882a593Smuzhiyun unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
3449*4882a593Smuzhiyun unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
3450*4882a593Smuzhiyun
3451*4882a593Smuzhiyun if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
3452*4882a593Smuzhiyun return 0;
3453*4882a593Smuzhiyun
3454*4882a593Smuzhiyun if (old->mnt_cifs_serverino_autodisabled)
3455*4882a593Smuzhiyun newflags &= ~CIFS_MOUNT_SERVER_INUM;
3456*4882a593Smuzhiyun
3457*4882a593Smuzhiyun if (oldflags != newflags)
3458*4882a593Smuzhiyun return 0;
3459*4882a593Smuzhiyun
3460*4882a593Smuzhiyun /*
3461*4882a593Smuzhiyun * We want to share sb only if we don't specify an r/wsize or
3462*4882a593Smuzhiyun * specified r/wsize is greater than or equal to existing one.
3463*4882a593Smuzhiyun */
3464*4882a593Smuzhiyun if (new->wsize && new->wsize < old->wsize)
3465*4882a593Smuzhiyun return 0;
3466*4882a593Smuzhiyun
3467*4882a593Smuzhiyun if (new->rsize && new->rsize < old->rsize)
3468*4882a593Smuzhiyun return 0;
3469*4882a593Smuzhiyun
3470*4882a593Smuzhiyun if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid))
3471*4882a593Smuzhiyun return 0;
3472*4882a593Smuzhiyun
3473*4882a593Smuzhiyun if (old->mnt_file_mode != new->mnt_file_mode ||
3474*4882a593Smuzhiyun old->mnt_dir_mode != new->mnt_dir_mode)
3475*4882a593Smuzhiyun return 0;
3476*4882a593Smuzhiyun
3477*4882a593Smuzhiyun if (strcmp(old->local_nls->charset, new->local_nls->charset))
3478*4882a593Smuzhiyun return 0;
3479*4882a593Smuzhiyun
3480*4882a593Smuzhiyun if (old->actimeo != new->actimeo)
3481*4882a593Smuzhiyun return 0;
3482*4882a593Smuzhiyun
3483*4882a593Smuzhiyun return 1;
3484*4882a593Smuzhiyun }
3485*4882a593Smuzhiyun
3486*4882a593Smuzhiyun static int
match_prepath(struct super_block * sb,struct cifs_mnt_data * mnt_data)3487*4882a593Smuzhiyun match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
3488*4882a593Smuzhiyun {
3489*4882a593Smuzhiyun struct cifs_sb_info *old = CIFS_SB(sb);
3490*4882a593Smuzhiyun struct cifs_sb_info *new = mnt_data->cifs_sb;
3491*4882a593Smuzhiyun bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
3492*4882a593Smuzhiyun old->prepath;
3493*4882a593Smuzhiyun bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
3494*4882a593Smuzhiyun new->prepath;
3495*4882a593Smuzhiyun
3496*4882a593Smuzhiyun if (old_set && new_set && !strcmp(new->prepath, old->prepath))
3497*4882a593Smuzhiyun return 1;
3498*4882a593Smuzhiyun else if (!old_set && !new_set)
3499*4882a593Smuzhiyun return 1;
3500*4882a593Smuzhiyun
3501*4882a593Smuzhiyun return 0;
3502*4882a593Smuzhiyun }
3503*4882a593Smuzhiyun
3504*4882a593Smuzhiyun int
cifs_match_super(struct super_block * sb,void * data)3505*4882a593Smuzhiyun cifs_match_super(struct super_block *sb, void *data)
3506*4882a593Smuzhiyun {
3507*4882a593Smuzhiyun struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
3508*4882a593Smuzhiyun struct smb_vol *volume_info;
3509*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb;
3510*4882a593Smuzhiyun struct TCP_Server_Info *tcp_srv;
3511*4882a593Smuzhiyun struct cifs_ses *ses;
3512*4882a593Smuzhiyun struct cifs_tcon *tcon;
3513*4882a593Smuzhiyun struct tcon_link *tlink;
3514*4882a593Smuzhiyun int rc = 0;
3515*4882a593Smuzhiyun
3516*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
3517*4882a593Smuzhiyun cifs_sb = CIFS_SB(sb);
3518*4882a593Smuzhiyun tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3519*4882a593Smuzhiyun if (tlink == NULL) {
3520*4882a593Smuzhiyun /* can not match superblock if tlink were ever null */
3521*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3522*4882a593Smuzhiyun return 0;
3523*4882a593Smuzhiyun }
3524*4882a593Smuzhiyun tcon = tlink_tcon(tlink);
3525*4882a593Smuzhiyun ses = tcon->ses;
3526*4882a593Smuzhiyun tcp_srv = ses->server;
3527*4882a593Smuzhiyun
3528*4882a593Smuzhiyun volume_info = mnt_data->vol;
3529*4882a593Smuzhiyun
3530*4882a593Smuzhiyun if (!match_server(tcp_srv, volume_info) ||
3531*4882a593Smuzhiyun !match_session(ses, volume_info) ||
3532*4882a593Smuzhiyun !match_tcon(tcon, volume_info) ||
3533*4882a593Smuzhiyun !match_prepath(sb, mnt_data)) {
3534*4882a593Smuzhiyun rc = 0;
3535*4882a593Smuzhiyun goto out;
3536*4882a593Smuzhiyun }
3537*4882a593Smuzhiyun
3538*4882a593Smuzhiyun rc = compare_mount_options(sb, mnt_data);
3539*4882a593Smuzhiyun out:
3540*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
3541*4882a593Smuzhiyun cifs_put_tlink(tlink);
3542*4882a593Smuzhiyun return rc;
3543*4882a593Smuzhiyun }
3544*4882a593Smuzhiyun
3545*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_LOCK_ALLOC
3546*4882a593Smuzhiyun static struct lock_class_key cifs_key[2];
3547*4882a593Smuzhiyun static struct lock_class_key cifs_slock_key[2];
3548*4882a593Smuzhiyun
3549*4882a593Smuzhiyun static inline void
cifs_reclassify_socket4(struct socket * sock)3550*4882a593Smuzhiyun cifs_reclassify_socket4(struct socket *sock)
3551*4882a593Smuzhiyun {
3552*4882a593Smuzhiyun struct sock *sk = sock->sk;
3553*4882a593Smuzhiyun BUG_ON(!sock_allow_reclassification(sk));
3554*4882a593Smuzhiyun sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
3555*4882a593Smuzhiyun &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
3556*4882a593Smuzhiyun }
3557*4882a593Smuzhiyun
3558*4882a593Smuzhiyun static inline void
cifs_reclassify_socket6(struct socket * sock)3559*4882a593Smuzhiyun cifs_reclassify_socket6(struct socket *sock)
3560*4882a593Smuzhiyun {
3561*4882a593Smuzhiyun struct sock *sk = sock->sk;
3562*4882a593Smuzhiyun BUG_ON(!sock_allow_reclassification(sk));
3563*4882a593Smuzhiyun sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
3564*4882a593Smuzhiyun &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
3565*4882a593Smuzhiyun }
3566*4882a593Smuzhiyun #else
3567*4882a593Smuzhiyun static inline void
cifs_reclassify_socket4(struct socket * sock)3568*4882a593Smuzhiyun cifs_reclassify_socket4(struct socket *sock)
3569*4882a593Smuzhiyun {
3570*4882a593Smuzhiyun }
3571*4882a593Smuzhiyun
3572*4882a593Smuzhiyun static inline void
cifs_reclassify_socket6(struct socket * sock)3573*4882a593Smuzhiyun cifs_reclassify_socket6(struct socket *sock)
3574*4882a593Smuzhiyun {
3575*4882a593Smuzhiyun }
3576*4882a593Smuzhiyun #endif
3577*4882a593Smuzhiyun
3578*4882a593Smuzhiyun /* See RFC1001 section 14 on representation of Netbios names */
rfc1002mangle(char * target,char * source,unsigned int length)3579*4882a593Smuzhiyun static void rfc1002mangle(char *target, char *source, unsigned int length)
3580*4882a593Smuzhiyun {
3581*4882a593Smuzhiyun unsigned int i, j;
3582*4882a593Smuzhiyun
3583*4882a593Smuzhiyun for (i = 0, j = 0; i < (length); i++) {
3584*4882a593Smuzhiyun /* mask a nibble at a time and encode */
3585*4882a593Smuzhiyun target[j] = 'A' + (0x0F & (source[i] >> 4));
3586*4882a593Smuzhiyun target[j+1] = 'A' + (0x0F & source[i]);
3587*4882a593Smuzhiyun j += 2;
3588*4882a593Smuzhiyun }
3589*4882a593Smuzhiyun
3590*4882a593Smuzhiyun }
3591*4882a593Smuzhiyun
3592*4882a593Smuzhiyun static int
bind_socket(struct TCP_Server_Info * server)3593*4882a593Smuzhiyun bind_socket(struct TCP_Server_Info *server)
3594*4882a593Smuzhiyun {
3595*4882a593Smuzhiyun int rc = 0;
3596*4882a593Smuzhiyun if (server->srcaddr.ss_family != AF_UNSPEC) {
3597*4882a593Smuzhiyun /* Bind to the specified local IP address */
3598*4882a593Smuzhiyun struct socket *socket = server->ssocket;
3599*4882a593Smuzhiyun rc = socket->ops->bind(socket,
3600*4882a593Smuzhiyun (struct sockaddr *) &server->srcaddr,
3601*4882a593Smuzhiyun sizeof(server->srcaddr));
3602*4882a593Smuzhiyun if (rc < 0) {
3603*4882a593Smuzhiyun struct sockaddr_in *saddr4;
3604*4882a593Smuzhiyun struct sockaddr_in6 *saddr6;
3605*4882a593Smuzhiyun saddr4 = (struct sockaddr_in *)&server->srcaddr;
3606*4882a593Smuzhiyun saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
3607*4882a593Smuzhiyun if (saddr6->sin6_family == AF_INET6)
3608*4882a593Smuzhiyun cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
3609*4882a593Smuzhiyun &saddr6->sin6_addr, rc);
3610*4882a593Smuzhiyun else
3611*4882a593Smuzhiyun cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
3612*4882a593Smuzhiyun &saddr4->sin_addr.s_addr, rc);
3613*4882a593Smuzhiyun }
3614*4882a593Smuzhiyun }
3615*4882a593Smuzhiyun return rc;
3616*4882a593Smuzhiyun }
3617*4882a593Smuzhiyun
3618*4882a593Smuzhiyun static int
ip_rfc1001_connect(struct TCP_Server_Info * server)3619*4882a593Smuzhiyun ip_rfc1001_connect(struct TCP_Server_Info *server)
3620*4882a593Smuzhiyun {
3621*4882a593Smuzhiyun int rc = 0;
3622*4882a593Smuzhiyun /*
3623*4882a593Smuzhiyun * some servers require RFC1001 sessinit before sending
3624*4882a593Smuzhiyun * negprot - BB check reconnection in case where second
3625*4882a593Smuzhiyun * sessinit is sent but no second negprot
3626*4882a593Smuzhiyun */
3627*4882a593Smuzhiyun struct rfc1002_session_packet *ses_init_buf;
3628*4882a593Smuzhiyun struct smb_hdr *smb_buf;
3629*4882a593Smuzhiyun ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
3630*4882a593Smuzhiyun GFP_KERNEL);
3631*4882a593Smuzhiyun if (ses_init_buf) {
3632*4882a593Smuzhiyun ses_init_buf->trailer.session_req.called_len = 32;
3633*4882a593Smuzhiyun
3634*4882a593Smuzhiyun if (server->server_RFC1001_name[0] != 0)
3635*4882a593Smuzhiyun rfc1002mangle(ses_init_buf->trailer.
3636*4882a593Smuzhiyun session_req.called_name,
3637*4882a593Smuzhiyun server->server_RFC1001_name,
3638*4882a593Smuzhiyun RFC1001_NAME_LEN_WITH_NULL);
3639*4882a593Smuzhiyun else
3640*4882a593Smuzhiyun rfc1002mangle(ses_init_buf->trailer.
3641*4882a593Smuzhiyun session_req.called_name,
3642*4882a593Smuzhiyun DEFAULT_CIFS_CALLED_NAME,
3643*4882a593Smuzhiyun RFC1001_NAME_LEN_WITH_NULL);
3644*4882a593Smuzhiyun
3645*4882a593Smuzhiyun ses_init_buf->trailer.session_req.calling_len = 32;
3646*4882a593Smuzhiyun
3647*4882a593Smuzhiyun /*
3648*4882a593Smuzhiyun * calling name ends in null (byte 16) from old smb
3649*4882a593Smuzhiyun * convention.
3650*4882a593Smuzhiyun */
3651*4882a593Smuzhiyun if (server->workstation_RFC1001_name[0] != 0)
3652*4882a593Smuzhiyun rfc1002mangle(ses_init_buf->trailer.
3653*4882a593Smuzhiyun session_req.calling_name,
3654*4882a593Smuzhiyun server->workstation_RFC1001_name,
3655*4882a593Smuzhiyun RFC1001_NAME_LEN_WITH_NULL);
3656*4882a593Smuzhiyun else
3657*4882a593Smuzhiyun rfc1002mangle(ses_init_buf->trailer.
3658*4882a593Smuzhiyun session_req.calling_name,
3659*4882a593Smuzhiyun "LINUX_CIFS_CLNT",
3660*4882a593Smuzhiyun RFC1001_NAME_LEN_WITH_NULL);
3661*4882a593Smuzhiyun
3662*4882a593Smuzhiyun ses_init_buf->trailer.session_req.scope1 = 0;
3663*4882a593Smuzhiyun ses_init_buf->trailer.session_req.scope2 = 0;
3664*4882a593Smuzhiyun smb_buf = (struct smb_hdr *)ses_init_buf;
3665*4882a593Smuzhiyun
3666*4882a593Smuzhiyun /* sizeof RFC1002_SESSION_REQUEST with no scope */
3667*4882a593Smuzhiyun smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
3668*4882a593Smuzhiyun rc = smb_send(server, smb_buf, 0x44);
3669*4882a593Smuzhiyun kfree(ses_init_buf);
3670*4882a593Smuzhiyun /*
3671*4882a593Smuzhiyun * RFC1001 layer in at least one server
3672*4882a593Smuzhiyun * requires very short break before negprot
3673*4882a593Smuzhiyun * presumably because not expecting negprot
3674*4882a593Smuzhiyun * to follow so fast. This is a simple
3675*4882a593Smuzhiyun * solution that works without
3676*4882a593Smuzhiyun * complicating the code and causes no
3677*4882a593Smuzhiyun * significant slowing down on mount
3678*4882a593Smuzhiyun * for everyone else
3679*4882a593Smuzhiyun */
3680*4882a593Smuzhiyun usleep_range(1000, 2000);
3681*4882a593Smuzhiyun }
3682*4882a593Smuzhiyun /*
3683*4882a593Smuzhiyun * else the negprot may still work without this
3684*4882a593Smuzhiyun * even though malloc failed
3685*4882a593Smuzhiyun */
3686*4882a593Smuzhiyun
3687*4882a593Smuzhiyun return rc;
3688*4882a593Smuzhiyun }
3689*4882a593Smuzhiyun
3690*4882a593Smuzhiyun static int
generic_ip_connect(struct TCP_Server_Info * server)3691*4882a593Smuzhiyun generic_ip_connect(struct TCP_Server_Info *server)
3692*4882a593Smuzhiyun {
3693*4882a593Smuzhiyun int rc = 0;
3694*4882a593Smuzhiyun __be16 sport;
3695*4882a593Smuzhiyun int slen, sfamily;
3696*4882a593Smuzhiyun struct socket *socket = server->ssocket;
3697*4882a593Smuzhiyun struct sockaddr *saddr;
3698*4882a593Smuzhiyun
3699*4882a593Smuzhiyun saddr = (struct sockaddr *) &server->dstaddr;
3700*4882a593Smuzhiyun
3701*4882a593Smuzhiyun if (server->dstaddr.ss_family == AF_INET6) {
3702*4882a593Smuzhiyun struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr;
3703*4882a593Smuzhiyun
3704*4882a593Smuzhiyun sport = ipv6->sin6_port;
3705*4882a593Smuzhiyun slen = sizeof(struct sockaddr_in6);
3706*4882a593Smuzhiyun sfamily = AF_INET6;
3707*4882a593Smuzhiyun cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr,
3708*4882a593Smuzhiyun ntohs(sport));
3709*4882a593Smuzhiyun } else {
3710*4882a593Smuzhiyun struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr;
3711*4882a593Smuzhiyun
3712*4882a593Smuzhiyun sport = ipv4->sin_port;
3713*4882a593Smuzhiyun slen = sizeof(struct sockaddr_in);
3714*4882a593Smuzhiyun sfamily = AF_INET;
3715*4882a593Smuzhiyun cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr,
3716*4882a593Smuzhiyun ntohs(sport));
3717*4882a593Smuzhiyun }
3718*4882a593Smuzhiyun
3719*4882a593Smuzhiyun if (socket == NULL) {
3720*4882a593Smuzhiyun rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
3721*4882a593Smuzhiyun IPPROTO_TCP, &socket, 1);
3722*4882a593Smuzhiyun if (rc < 0) {
3723*4882a593Smuzhiyun cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
3724*4882a593Smuzhiyun server->ssocket = NULL;
3725*4882a593Smuzhiyun return rc;
3726*4882a593Smuzhiyun }
3727*4882a593Smuzhiyun
3728*4882a593Smuzhiyun /* BB other socket options to set KEEPALIVE, NODELAY? */
3729*4882a593Smuzhiyun cifs_dbg(FYI, "Socket created\n");
3730*4882a593Smuzhiyun server->ssocket = socket;
3731*4882a593Smuzhiyun socket->sk->sk_allocation = GFP_NOFS;
3732*4882a593Smuzhiyun if (sfamily == AF_INET6)
3733*4882a593Smuzhiyun cifs_reclassify_socket6(socket);
3734*4882a593Smuzhiyun else
3735*4882a593Smuzhiyun cifs_reclassify_socket4(socket);
3736*4882a593Smuzhiyun }
3737*4882a593Smuzhiyun
3738*4882a593Smuzhiyun rc = bind_socket(server);
3739*4882a593Smuzhiyun if (rc < 0)
3740*4882a593Smuzhiyun return rc;
3741*4882a593Smuzhiyun
3742*4882a593Smuzhiyun /*
3743*4882a593Smuzhiyun * Eventually check for other socket options to change from
3744*4882a593Smuzhiyun * the default. sock_setsockopt not used because it expects
3745*4882a593Smuzhiyun * user space buffer
3746*4882a593Smuzhiyun */
3747*4882a593Smuzhiyun socket->sk->sk_rcvtimeo = 7 * HZ;
3748*4882a593Smuzhiyun socket->sk->sk_sndtimeo = 5 * HZ;
3749*4882a593Smuzhiyun
3750*4882a593Smuzhiyun /* make the bufsizes depend on wsize/rsize and max requests */
3751*4882a593Smuzhiyun if (server->noautotune) {
3752*4882a593Smuzhiyun if (socket->sk->sk_sndbuf < (200 * 1024))
3753*4882a593Smuzhiyun socket->sk->sk_sndbuf = 200 * 1024;
3754*4882a593Smuzhiyun if (socket->sk->sk_rcvbuf < (140 * 1024))
3755*4882a593Smuzhiyun socket->sk->sk_rcvbuf = 140 * 1024;
3756*4882a593Smuzhiyun }
3757*4882a593Smuzhiyun
3758*4882a593Smuzhiyun if (server->tcp_nodelay)
3759*4882a593Smuzhiyun tcp_sock_set_nodelay(socket->sk);
3760*4882a593Smuzhiyun
3761*4882a593Smuzhiyun cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n",
3762*4882a593Smuzhiyun socket->sk->sk_sndbuf,
3763*4882a593Smuzhiyun socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
3764*4882a593Smuzhiyun
3765*4882a593Smuzhiyun rc = socket->ops->connect(socket, saddr, slen,
3766*4882a593Smuzhiyun server->noblockcnt ? O_NONBLOCK : 0);
3767*4882a593Smuzhiyun /*
3768*4882a593Smuzhiyun * When mounting SMB root file systems, we do not want to block in
3769*4882a593Smuzhiyun * connect. Otherwise bail out and then let cifs_reconnect() perform
3770*4882a593Smuzhiyun * reconnect failover - if possible.
3771*4882a593Smuzhiyun */
3772*4882a593Smuzhiyun if (server->noblockcnt && rc == -EINPROGRESS)
3773*4882a593Smuzhiyun rc = 0;
3774*4882a593Smuzhiyun if (rc < 0) {
3775*4882a593Smuzhiyun cifs_dbg(FYI, "Error %d connecting to server\n", rc);
3776*4882a593Smuzhiyun sock_release(socket);
3777*4882a593Smuzhiyun server->ssocket = NULL;
3778*4882a593Smuzhiyun return rc;
3779*4882a593Smuzhiyun }
3780*4882a593Smuzhiyun
3781*4882a593Smuzhiyun if (sport == htons(RFC1001_PORT))
3782*4882a593Smuzhiyun rc = ip_rfc1001_connect(server);
3783*4882a593Smuzhiyun
3784*4882a593Smuzhiyun return rc;
3785*4882a593Smuzhiyun }
3786*4882a593Smuzhiyun
3787*4882a593Smuzhiyun static int
ip_connect(struct TCP_Server_Info * server)3788*4882a593Smuzhiyun ip_connect(struct TCP_Server_Info *server)
3789*4882a593Smuzhiyun {
3790*4882a593Smuzhiyun __be16 *sport;
3791*4882a593Smuzhiyun struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
3792*4882a593Smuzhiyun struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3793*4882a593Smuzhiyun
3794*4882a593Smuzhiyun if (server->dstaddr.ss_family == AF_INET6)
3795*4882a593Smuzhiyun sport = &addr6->sin6_port;
3796*4882a593Smuzhiyun else
3797*4882a593Smuzhiyun sport = &addr->sin_port;
3798*4882a593Smuzhiyun
3799*4882a593Smuzhiyun if (*sport == 0) {
3800*4882a593Smuzhiyun int rc;
3801*4882a593Smuzhiyun
3802*4882a593Smuzhiyun /* try with 445 port at first */
3803*4882a593Smuzhiyun *sport = htons(CIFS_PORT);
3804*4882a593Smuzhiyun
3805*4882a593Smuzhiyun rc = generic_ip_connect(server);
3806*4882a593Smuzhiyun if (rc >= 0)
3807*4882a593Smuzhiyun return rc;
3808*4882a593Smuzhiyun
3809*4882a593Smuzhiyun /* if it failed, try with 139 port */
3810*4882a593Smuzhiyun *sport = htons(RFC1001_PORT);
3811*4882a593Smuzhiyun }
3812*4882a593Smuzhiyun
3813*4882a593Smuzhiyun return generic_ip_connect(server);
3814*4882a593Smuzhiyun }
3815*4882a593Smuzhiyun
reset_cifs_unix_caps(unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,struct smb_vol * vol_info)3816*4882a593Smuzhiyun void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
3817*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info)
3818*4882a593Smuzhiyun {
3819*4882a593Smuzhiyun /* if we are reconnecting then should we check to see if
3820*4882a593Smuzhiyun * any requested capabilities changed locally e.g. via
3821*4882a593Smuzhiyun * remount but we can not do much about it here
3822*4882a593Smuzhiyun * if they have (even if we could detect it by the following)
3823*4882a593Smuzhiyun * Perhaps we could add a backpointer to array of sb from tcon
3824*4882a593Smuzhiyun * or if we change to make all sb to same share the same
3825*4882a593Smuzhiyun * sb as NFS - then we only have one backpointer to sb.
3826*4882a593Smuzhiyun * What if we wanted to mount the server share twice once with
3827*4882a593Smuzhiyun * and once without posixacls or posix paths? */
3828*4882a593Smuzhiyun __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
3829*4882a593Smuzhiyun
3830*4882a593Smuzhiyun if (vol_info && vol_info->no_linux_ext) {
3831*4882a593Smuzhiyun tcon->fsUnixInfo.Capability = 0;
3832*4882a593Smuzhiyun tcon->unix_ext = 0; /* Unix Extensions disabled */
3833*4882a593Smuzhiyun cifs_dbg(FYI, "Linux protocol extensions disabled\n");
3834*4882a593Smuzhiyun return;
3835*4882a593Smuzhiyun } else if (vol_info)
3836*4882a593Smuzhiyun tcon->unix_ext = 1; /* Unix Extensions supported */
3837*4882a593Smuzhiyun
3838*4882a593Smuzhiyun if (tcon->unix_ext == 0) {
3839*4882a593Smuzhiyun cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
3840*4882a593Smuzhiyun return;
3841*4882a593Smuzhiyun }
3842*4882a593Smuzhiyun
3843*4882a593Smuzhiyun if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
3844*4882a593Smuzhiyun __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
3845*4882a593Smuzhiyun cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
3846*4882a593Smuzhiyun /* check for reconnect case in which we do not
3847*4882a593Smuzhiyun want to change the mount behavior if we can avoid it */
3848*4882a593Smuzhiyun if (vol_info == NULL) {
3849*4882a593Smuzhiyun /* turn off POSIX ACL and PATHNAMES if not set
3850*4882a593Smuzhiyun originally at mount time */
3851*4882a593Smuzhiyun if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
3852*4882a593Smuzhiyun cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
3853*4882a593Smuzhiyun if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
3854*4882a593Smuzhiyun if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
3855*4882a593Smuzhiyun cifs_dbg(VFS, "POSIXPATH support change\n");
3856*4882a593Smuzhiyun cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
3857*4882a593Smuzhiyun } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
3858*4882a593Smuzhiyun cifs_dbg(VFS, "possible reconnect error\n");
3859*4882a593Smuzhiyun cifs_dbg(VFS, "server disabled POSIX path support\n");
3860*4882a593Smuzhiyun }
3861*4882a593Smuzhiyun }
3862*4882a593Smuzhiyun
3863*4882a593Smuzhiyun if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3864*4882a593Smuzhiyun cifs_dbg(VFS, "per-share encryption not supported yet\n");
3865*4882a593Smuzhiyun
3866*4882a593Smuzhiyun cap &= CIFS_UNIX_CAP_MASK;
3867*4882a593Smuzhiyun if (vol_info && vol_info->no_psx_acl)
3868*4882a593Smuzhiyun cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
3869*4882a593Smuzhiyun else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
3870*4882a593Smuzhiyun cifs_dbg(FYI, "negotiated posix acl support\n");
3871*4882a593Smuzhiyun if (cifs_sb)
3872*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |=
3873*4882a593Smuzhiyun CIFS_MOUNT_POSIXACL;
3874*4882a593Smuzhiyun }
3875*4882a593Smuzhiyun
3876*4882a593Smuzhiyun if (vol_info && vol_info->posix_paths == 0)
3877*4882a593Smuzhiyun cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
3878*4882a593Smuzhiyun else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3879*4882a593Smuzhiyun cifs_dbg(FYI, "negotiate posix pathnames\n");
3880*4882a593Smuzhiyun if (cifs_sb)
3881*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |=
3882*4882a593Smuzhiyun CIFS_MOUNT_POSIX_PATHS;
3883*4882a593Smuzhiyun }
3884*4882a593Smuzhiyun
3885*4882a593Smuzhiyun cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
3886*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DEBUG2
3887*4882a593Smuzhiyun if (cap & CIFS_UNIX_FCNTL_CAP)
3888*4882a593Smuzhiyun cifs_dbg(FYI, "FCNTL cap\n");
3889*4882a593Smuzhiyun if (cap & CIFS_UNIX_EXTATTR_CAP)
3890*4882a593Smuzhiyun cifs_dbg(FYI, "EXTATTR cap\n");
3891*4882a593Smuzhiyun if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
3892*4882a593Smuzhiyun cifs_dbg(FYI, "POSIX path cap\n");
3893*4882a593Smuzhiyun if (cap & CIFS_UNIX_XATTR_CAP)
3894*4882a593Smuzhiyun cifs_dbg(FYI, "XATTR cap\n");
3895*4882a593Smuzhiyun if (cap & CIFS_UNIX_POSIX_ACL_CAP)
3896*4882a593Smuzhiyun cifs_dbg(FYI, "POSIX ACL cap\n");
3897*4882a593Smuzhiyun if (cap & CIFS_UNIX_LARGE_READ_CAP)
3898*4882a593Smuzhiyun cifs_dbg(FYI, "very large read cap\n");
3899*4882a593Smuzhiyun if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
3900*4882a593Smuzhiyun cifs_dbg(FYI, "very large write cap\n");
3901*4882a593Smuzhiyun if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
3902*4882a593Smuzhiyun cifs_dbg(FYI, "transport encryption cap\n");
3903*4882a593Smuzhiyun if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3904*4882a593Smuzhiyun cifs_dbg(FYI, "mandatory transport encryption cap\n");
3905*4882a593Smuzhiyun #endif /* CIFS_DEBUG2 */
3906*4882a593Smuzhiyun if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
3907*4882a593Smuzhiyun if (vol_info == NULL) {
3908*4882a593Smuzhiyun cifs_dbg(FYI, "resetting capabilities failed\n");
3909*4882a593Smuzhiyun } else
3910*4882a593Smuzhiyun cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n");
3911*4882a593Smuzhiyun
3912*4882a593Smuzhiyun }
3913*4882a593Smuzhiyun }
3914*4882a593Smuzhiyun }
3915*4882a593Smuzhiyun
cifs_setup_cifs_sb(struct smb_vol * pvolume_info,struct cifs_sb_info * cifs_sb)3916*4882a593Smuzhiyun int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3917*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb)
3918*4882a593Smuzhiyun {
3919*4882a593Smuzhiyun INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
3920*4882a593Smuzhiyun
3921*4882a593Smuzhiyun spin_lock_init(&cifs_sb->tlink_tree_lock);
3922*4882a593Smuzhiyun cifs_sb->tlink_tree = RB_ROOT;
3923*4882a593Smuzhiyun
3924*4882a593Smuzhiyun cifs_sb->bsize = pvolume_info->bsize;
3925*4882a593Smuzhiyun /*
3926*4882a593Smuzhiyun * Temporarily set r/wsize for matching superblock. If we end up using
3927*4882a593Smuzhiyun * new sb then client will later negotiate it downward if needed.
3928*4882a593Smuzhiyun */
3929*4882a593Smuzhiyun cifs_sb->rsize = pvolume_info->rsize;
3930*4882a593Smuzhiyun cifs_sb->wsize = pvolume_info->wsize;
3931*4882a593Smuzhiyun
3932*4882a593Smuzhiyun cifs_sb->mnt_uid = pvolume_info->linux_uid;
3933*4882a593Smuzhiyun cifs_sb->mnt_gid = pvolume_info->linux_gid;
3934*4882a593Smuzhiyun cifs_sb->mnt_file_mode = pvolume_info->file_mode;
3935*4882a593Smuzhiyun cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
3936*4882a593Smuzhiyun cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n",
3937*4882a593Smuzhiyun cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
3938*4882a593Smuzhiyun
3939*4882a593Smuzhiyun cifs_sb->actimeo = pvolume_info->actimeo;
3940*4882a593Smuzhiyun cifs_sb->local_nls = pvolume_info->local_nls;
3941*4882a593Smuzhiyun
3942*4882a593Smuzhiyun if (pvolume_info->nodfs)
3943*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
3944*4882a593Smuzhiyun if (pvolume_info->noperm)
3945*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
3946*4882a593Smuzhiyun if (pvolume_info->setuids)
3947*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
3948*4882a593Smuzhiyun if (pvolume_info->setuidfromacl)
3949*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
3950*4882a593Smuzhiyun if (pvolume_info->server_ino)
3951*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
3952*4882a593Smuzhiyun if (pvolume_info->remap)
3953*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
3954*4882a593Smuzhiyun if (pvolume_info->sfu_remap)
3955*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
3956*4882a593Smuzhiyun if (pvolume_info->no_xattr)
3957*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
3958*4882a593Smuzhiyun if (pvolume_info->sfu_emul)
3959*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
3960*4882a593Smuzhiyun if (pvolume_info->nobrl)
3961*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
3962*4882a593Smuzhiyun if (pvolume_info->nohandlecache)
3963*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
3964*4882a593Smuzhiyun if (pvolume_info->nostrictsync)
3965*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
3966*4882a593Smuzhiyun if (pvolume_info->mand_lock)
3967*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
3968*4882a593Smuzhiyun if (pvolume_info->rwpidforward)
3969*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
3970*4882a593Smuzhiyun if (pvolume_info->mode_ace)
3971*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
3972*4882a593Smuzhiyun if (pvolume_info->cifs_acl)
3973*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
3974*4882a593Smuzhiyun if (pvolume_info->backupuid_specified) {
3975*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
3976*4882a593Smuzhiyun cifs_sb->mnt_backupuid = pvolume_info->backupuid;
3977*4882a593Smuzhiyun }
3978*4882a593Smuzhiyun if (pvolume_info->backupgid_specified) {
3979*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
3980*4882a593Smuzhiyun cifs_sb->mnt_backupgid = pvolume_info->backupgid;
3981*4882a593Smuzhiyun }
3982*4882a593Smuzhiyun if (pvolume_info->override_uid)
3983*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
3984*4882a593Smuzhiyun if (pvolume_info->override_gid)
3985*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
3986*4882a593Smuzhiyun if (pvolume_info->dynperm)
3987*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
3988*4882a593Smuzhiyun if (pvolume_info->fsc)
3989*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
3990*4882a593Smuzhiyun if (pvolume_info->multiuser)
3991*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
3992*4882a593Smuzhiyun CIFS_MOUNT_NO_PERM);
3993*4882a593Smuzhiyun if (pvolume_info->strict_io)
3994*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
3995*4882a593Smuzhiyun if (pvolume_info->direct_io) {
3996*4882a593Smuzhiyun cifs_dbg(FYI, "mounting share using direct i/o\n");
3997*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
3998*4882a593Smuzhiyun }
3999*4882a593Smuzhiyun if (pvolume_info->cache_ro) {
4000*4882a593Smuzhiyun cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
4001*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
4002*4882a593Smuzhiyun } else if (pvolume_info->cache_rw) {
4003*4882a593Smuzhiyun cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
4004*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
4005*4882a593Smuzhiyun CIFS_MOUNT_RW_CACHE);
4006*4882a593Smuzhiyun }
4007*4882a593Smuzhiyun if (pvolume_info->mfsymlinks) {
4008*4882a593Smuzhiyun if (pvolume_info->sfu_emul) {
4009*4882a593Smuzhiyun /*
4010*4882a593Smuzhiyun * Our SFU ("Services for Unix" emulation does not allow
4011*4882a593Smuzhiyun * creating symlinks but does allow reading existing SFU
4012*4882a593Smuzhiyun * symlinks (it does allow both creating and reading SFU
4013*4882a593Smuzhiyun * style mknod and FIFOs though). When "mfsymlinks" and
4014*4882a593Smuzhiyun * "sfu" are both enabled at the same time, it allows
4015*4882a593Smuzhiyun * reading both types of symlinks, but will only create
4016*4882a593Smuzhiyun * them with mfsymlinks format. This allows better
4017*4882a593Smuzhiyun * Apple compatibility (probably better for Samba too)
4018*4882a593Smuzhiyun * while still recognizing old Windows style symlinks.
4019*4882a593Smuzhiyun */
4020*4882a593Smuzhiyun cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
4023*4882a593Smuzhiyun }
4024*4882a593Smuzhiyun
4025*4882a593Smuzhiyun if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
4026*4882a593Smuzhiyun cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n");
4027*4882a593Smuzhiyun
4028*4882a593Smuzhiyun if (pvolume_info->prepath) {
4029*4882a593Smuzhiyun cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL);
4030*4882a593Smuzhiyun if (cifs_sb->prepath == NULL)
4031*4882a593Smuzhiyun return -ENOMEM;
4032*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4033*4882a593Smuzhiyun }
4034*4882a593Smuzhiyun
4035*4882a593Smuzhiyun return 0;
4036*4882a593Smuzhiyun }
4037*4882a593Smuzhiyun
4038*4882a593Smuzhiyun void
cifs_cleanup_volume_info_contents(struct smb_vol * volume_info)4039*4882a593Smuzhiyun cifs_cleanup_volume_info_contents(struct smb_vol *volume_info)
4040*4882a593Smuzhiyun {
4041*4882a593Smuzhiyun kfree(volume_info->username);
4042*4882a593Smuzhiyun kfree_sensitive(volume_info->password);
4043*4882a593Smuzhiyun kfree(volume_info->UNC);
4044*4882a593Smuzhiyun kfree(volume_info->domainname);
4045*4882a593Smuzhiyun kfree(volume_info->iocharset);
4046*4882a593Smuzhiyun kfree(volume_info->prepath);
4047*4882a593Smuzhiyun }
4048*4882a593Smuzhiyun
4049*4882a593Smuzhiyun void
cifs_cleanup_volume_info(struct smb_vol * volume_info)4050*4882a593Smuzhiyun cifs_cleanup_volume_info(struct smb_vol *volume_info)
4051*4882a593Smuzhiyun {
4052*4882a593Smuzhiyun if (!volume_info)
4053*4882a593Smuzhiyun return;
4054*4882a593Smuzhiyun cifs_cleanup_volume_info_contents(volume_info);
4055*4882a593Smuzhiyun kfree(volume_info);
4056*4882a593Smuzhiyun }
4057*4882a593Smuzhiyun
4058*4882a593Smuzhiyun /* Release all succeed connections */
mount_put_conns(struct cifs_sb_info * cifs_sb,unsigned int xid,struct TCP_Server_Info * server,struct cifs_ses * ses,struct cifs_tcon * tcon)4059*4882a593Smuzhiyun static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
4060*4882a593Smuzhiyun unsigned int xid,
4061*4882a593Smuzhiyun struct TCP_Server_Info *server,
4062*4882a593Smuzhiyun struct cifs_ses *ses, struct cifs_tcon *tcon)
4063*4882a593Smuzhiyun {
4064*4882a593Smuzhiyun int rc = 0;
4065*4882a593Smuzhiyun
4066*4882a593Smuzhiyun if (tcon)
4067*4882a593Smuzhiyun cifs_put_tcon(tcon);
4068*4882a593Smuzhiyun else if (ses)
4069*4882a593Smuzhiyun cifs_put_smb_ses(ses);
4070*4882a593Smuzhiyun else if (server)
4071*4882a593Smuzhiyun cifs_put_tcp_session(server, 0);
4072*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
4073*4882a593Smuzhiyun free_xid(xid);
4074*4882a593Smuzhiyun }
4075*4882a593Smuzhiyun
4076*4882a593Smuzhiyun /* Get connections for tcp, ses and tcon */
mount_get_conns(struct smb_vol * vol,struct cifs_sb_info * cifs_sb,unsigned int * xid,struct TCP_Server_Info ** nserver,struct cifs_ses ** nses,struct cifs_tcon ** ntcon)4077*4882a593Smuzhiyun static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
4078*4882a593Smuzhiyun unsigned int *xid,
4079*4882a593Smuzhiyun struct TCP_Server_Info **nserver,
4080*4882a593Smuzhiyun struct cifs_ses **nses, struct cifs_tcon **ntcon)
4081*4882a593Smuzhiyun {
4082*4882a593Smuzhiyun int rc = 0;
4083*4882a593Smuzhiyun struct TCP_Server_Info *server;
4084*4882a593Smuzhiyun struct cifs_ses *ses;
4085*4882a593Smuzhiyun struct cifs_tcon *tcon;
4086*4882a593Smuzhiyun
4087*4882a593Smuzhiyun *nserver = NULL;
4088*4882a593Smuzhiyun *nses = NULL;
4089*4882a593Smuzhiyun *ntcon = NULL;
4090*4882a593Smuzhiyun
4091*4882a593Smuzhiyun *xid = get_xid();
4092*4882a593Smuzhiyun
4093*4882a593Smuzhiyun /* get a reference to a tcp session */
4094*4882a593Smuzhiyun server = cifs_get_tcp_session(vol);
4095*4882a593Smuzhiyun if (IS_ERR(server)) {
4096*4882a593Smuzhiyun rc = PTR_ERR(server);
4097*4882a593Smuzhiyun return rc;
4098*4882a593Smuzhiyun }
4099*4882a593Smuzhiyun
4100*4882a593Smuzhiyun *nserver = server;
4101*4882a593Smuzhiyun
4102*4882a593Smuzhiyun /* get a reference to a SMB session */
4103*4882a593Smuzhiyun ses = cifs_get_smb_ses(server, vol);
4104*4882a593Smuzhiyun if (IS_ERR(ses)) {
4105*4882a593Smuzhiyun rc = PTR_ERR(ses);
4106*4882a593Smuzhiyun return rc;
4107*4882a593Smuzhiyun }
4108*4882a593Smuzhiyun
4109*4882a593Smuzhiyun *nses = ses;
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun if ((vol->persistent == true) && (!(ses->server->capabilities &
4112*4882a593Smuzhiyun SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
4113*4882a593Smuzhiyun cifs_server_dbg(VFS, "persistent handles not supported by server\n");
4114*4882a593Smuzhiyun return -EOPNOTSUPP;
4115*4882a593Smuzhiyun }
4116*4882a593Smuzhiyun
4117*4882a593Smuzhiyun /* search for existing tcon to this server share */
4118*4882a593Smuzhiyun tcon = cifs_get_tcon(ses, vol);
4119*4882a593Smuzhiyun if (IS_ERR(tcon)) {
4120*4882a593Smuzhiyun rc = PTR_ERR(tcon);
4121*4882a593Smuzhiyun return rc;
4122*4882a593Smuzhiyun }
4123*4882a593Smuzhiyun
4124*4882a593Smuzhiyun *ntcon = tcon;
4125*4882a593Smuzhiyun
4126*4882a593Smuzhiyun /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
4127*4882a593Smuzhiyun if (tcon->posix_extensions)
4128*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
4129*4882a593Smuzhiyun
4130*4882a593Smuzhiyun /* tell server which Unix caps we support */
4131*4882a593Smuzhiyun if (cap_unix(tcon->ses)) {
4132*4882a593Smuzhiyun /*
4133*4882a593Smuzhiyun * reset of caps checks mount to see if unix extensions disabled
4134*4882a593Smuzhiyun * for just this mount.
4135*4882a593Smuzhiyun */
4136*4882a593Smuzhiyun reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol);
4137*4882a593Smuzhiyun if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
4138*4882a593Smuzhiyun (le64_to_cpu(tcon->fsUnixInfo.Capability) &
4139*4882a593Smuzhiyun CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
4140*4882a593Smuzhiyun return -EACCES;
4141*4882a593Smuzhiyun } else
4142*4882a593Smuzhiyun tcon->unix_ext = 0; /* server does not support them */
4143*4882a593Smuzhiyun
4144*4882a593Smuzhiyun /* do not care if a following call succeed - informational */
4145*4882a593Smuzhiyun if (!tcon->pipe && server->ops->qfs_tcon) {
4146*4882a593Smuzhiyun server->ops->qfs_tcon(*xid, tcon, cifs_sb);
4147*4882a593Smuzhiyun if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
4148*4882a593Smuzhiyun if (tcon->fsDevInfo.DeviceCharacteristics &
4149*4882a593Smuzhiyun cpu_to_le32(FILE_READ_ONLY_DEVICE))
4150*4882a593Smuzhiyun cifs_dbg(VFS, "mounted to read only share\n");
4151*4882a593Smuzhiyun else if ((cifs_sb->mnt_cifs_flags &
4152*4882a593Smuzhiyun CIFS_MOUNT_RW_CACHE) == 0)
4153*4882a593Smuzhiyun cifs_dbg(VFS, "read only mount of RW share\n");
4154*4882a593Smuzhiyun /* no need to log a RW mount of a typical RW share */
4155*4882a593Smuzhiyun }
4156*4882a593Smuzhiyun }
4157*4882a593Smuzhiyun
4158*4882a593Smuzhiyun cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
4159*4882a593Smuzhiyun cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
4160*4882a593Smuzhiyun
4161*4882a593Smuzhiyun return 0;
4162*4882a593Smuzhiyun }
4163*4882a593Smuzhiyun
mount_setup_tlink(struct cifs_sb_info * cifs_sb,struct cifs_ses * ses,struct cifs_tcon * tcon)4164*4882a593Smuzhiyun static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
4165*4882a593Smuzhiyun struct cifs_tcon *tcon)
4166*4882a593Smuzhiyun {
4167*4882a593Smuzhiyun struct tcon_link *tlink;
4168*4882a593Smuzhiyun
4169*4882a593Smuzhiyun /* hang the tcon off of the superblock */
4170*4882a593Smuzhiyun tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
4171*4882a593Smuzhiyun if (tlink == NULL)
4172*4882a593Smuzhiyun return -ENOMEM;
4173*4882a593Smuzhiyun
4174*4882a593Smuzhiyun tlink->tl_uid = ses->linux_uid;
4175*4882a593Smuzhiyun tlink->tl_tcon = tcon;
4176*4882a593Smuzhiyun tlink->tl_time = jiffies;
4177*4882a593Smuzhiyun set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
4178*4882a593Smuzhiyun set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4179*4882a593Smuzhiyun
4180*4882a593Smuzhiyun cifs_sb->master_tlink = tlink;
4181*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
4182*4882a593Smuzhiyun tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
4183*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
4184*4882a593Smuzhiyun
4185*4882a593Smuzhiyun queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
4186*4882a593Smuzhiyun TLINK_IDLE_EXPIRE);
4187*4882a593Smuzhiyun return 0;
4188*4882a593Smuzhiyun }
4189*4882a593Smuzhiyun
4190*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
4191*4882a593Smuzhiyun /*
4192*4882a593Smuzhiyun * cifs_build_path_to_root returns full path to root when we do not have an
4193*4882a593Smuzhiyun * exiting connection (tcon)
4194*4882a593Smuzhiyun */
4195*4882a593Smuzhiyun static char *
build_unc_path_to_root(const struct smb_vol * vol,const struct cifs_sb_info * cifs_sb,bool useppath)4196*4882a593Smuzhiyun build_unc_path_to_root(const struct smb_vol *vol,
4197*4882a593Smuzhiyun const struct cifs_sb_info *cifs_sb, bool useppath)
4198*4882a593Smuzhiyun {
4199*4882a593Smuzhiyun char *full_path, *pos;
4200*4882a593Smuzhiyun unsigned int pplen = useppath && vol->prepath ?
4201*4882a593Smuzhiyun strlen(vol->prepath) + 1 : 0;
4202*4882a593Smuzhiyun unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1);
4203*4882a593Smuzhiyun
4204*4882a593Smuzhiyun if (unc_len > MAX_TREE_SIZE)
4205*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
4206*4882a593Smuzhiyun
4207*4882a593Smuzhiyun full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
4208*4882a593Smuzhiyun if (full_path == NULL)
4209*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
4210*4882a593Smuzhiyun
4211*4882a593Smuzhiyun memcpy(full_path, vol->UNC, unc_len);
4212*4882a593Smuzhiyun pos = full_path + unc_len;
4213*4882a593Smuzhiyun
4214*4882a593Smuzhiyun if (pplen) {
4215*4882a593Smuzhiyun *pos = CIFS_DIR_SEP(cifs_sb);
4216*4882a593Smuzhiyun memcpy(pos + 1, vol->prepath, pplen);
4217*4882a593Smuzhiyun pos += pplen;
4218*4882a593Smuzhiyun }
4219*4882a593Smuzhiyun
4220*4882a593Smuzhiyun *pos = '\0'; /* add trailing null */
4221*4882a593Smuzhiyun convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
4222*4882a593Smuzhiyun cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path);
4223*4882a593Smuzhiyun return full_path;
4224*4882a593Smuzhiyun }
4225*4882a593Smuzhiyun
4226*4882a593Smuzhiyun /**
4227*4882a593Smuzhiyun * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb
4228*4882a593Smuzhiyun *
4229*4882a593Smuzhiyun *
4230*4882a593Smuzhiyun * If a referral is found, cifs_sb->mountdata will be (re-)allocated
4231*4882a593Smuzhiyun * to a string containing updated options for the submount. Otherwise it
4232*4882a593Smuzhiyun * will be left untouched.
4233*4882a593Smuzhiyun *
4234*4882a593Smuzhiyun * Returns the rc from get_dfs_path to the caller, which can be used to
4235*4882a593Smuzhiyun * determine whether there were referrals.
4236*4882a593Smuzhiyun */
4237*4882a593Smuzhiyun static int
expand_dfs_referral(const unsigned int xid,struct cifs_ses * ses,struct smb_vol * volume_info,struct cifs_sb_info * cifs_sb,char * ref_path)4238*4882a593Smuzhiyun expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
4239*4882a593Smuzhiyun struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
4240*4882a593Smuzhiyun char *ref_path)
4241*4882a593Smuzhiyun {
4242*4882a593Smuzhiyun int rc;
4243*4882a593Smuzhiyun struct dfs_info3_param referral = {0};
4244*4882a593Smuzhiyun char *full_path = NULL, *mdata = NULL;
4245*4882a593Smuzhiyun
4246*4882a593Smuzhiyun if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
4247*4882a593Smuzhiyun return -EREMOTE;
4248*4882a593Smuzhiyun
4249*4882a593Smuzhiyun full_path = build_unc_path_to_root(volume_info, cifs_sb, true);
4250*4882a593Smuzhiyun if (IS_ERR(full_path))
4251*4882a593Smuzhiyun return PTR_ERR(full_path);
4252*4882a593Smuzhiyun
4253*4882a593Smuzhiyun rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
4254*4882a593Smuzhiyun ref_path, &referral, NULL);
4255*4882a593Smuzhiyun if (!rc) {
4256*4882a593Smuzhiyun char *fake_devname = NULL;
4257*4882a593Smuzhiyun
4258*4882a593Smuzhiyun mdata = cifs_compose_mount_options(cifs_sb->mountdata,
4259*4882a593Smuzhiyun full_path + 1, &referral,
4260*4882a593Smuzhiyun &fake_devname);
4261*4882a593Smuzhiyun free_dfs_info_param(&referral);
4262*4882a593Smuzhiyun
4263*4882a593Smuzhiyun if (IS_ERR(mdata)) {
4264*4882a593Smuzhiyun rc = PTR_ERR(mdata);
4265*4882a593Smuzhiyun mdata = NULL;
4266*4882a593Smuzhiyun } else {
4267*4882a593Smuzhiyun cifs_cleanup_volume_info_contents(volume_info);
4268*4882a593Smuzhiyun rc = cifs_setup_volume_info(volume_info, mdata,
4269*4882a593Smuzhiyun fake_devname, false);
4270*4882a593Smuzhiyun }
4271*4882a593Smuzhiyun kfree(fake_devname);
4272*4882a593Smuzhiyun kfree(cifs_sb->mountdata);
4273*4882a593Smuzhiyun cifs_sb->mountdata = mdata;
4274*4882a593Smuzhiyun }
4275*4882a593Smuzhiyun kfree(full_path);
4276*4882a593Smuzhiyun return rc;
4277*4882a593Smuzhiyun }
4278*4882a593Smuzhiyun
get_next_dfs_tgt(const char * path,struct dfs_cache_tgt_list * tgt_list,struct dfs_cache_tgt_iterator ** tgt_it)4279*4882a593Smuzhiyun static inline int get_next_dfs_tgt(const char *path,
4280*4882a593Smuzhiyun struct dfs_cache_tgt_list *tgt_list,
4281*4882a593Smuzhiyun struct dfs_cache_tgt_iterator **tgt_it)
4282*4882a593Smuzhiyun {
4283*4882a593Smuzhiyun if (!*tgt_it)
4284*4882a593Smuzhiyun *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
4285*4882a593Smuzhiyun else
4286*4882a593Smuzhiyun *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
4287*4882a593Smuzhiyun return !*tgt_it ? -EHOSTDOWN : 0;
4288*4882a593Smuzhiyun }
4289*4882a593Smuzhiyun
update_vol_info(const struct dfs_cache_tgt_iterator * tgt_it,struct smb_vol * fake_vol,struct smb_vol * vol)4290*4882a593Smuzhiyun static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
4291*4882a593Smuzhiyun struct smb_vol *fake_vol, struct smb_vol *vol)
4292*4882a593Smuzhiyun {
4293*4882a593Smuzhiyun const char *tgt = dfs_cache_get_tgt_name(tgt_it);
4294*4882a593Smuzhiyun int len = strlen(tgt) + 2;
4295*4882a593Smuzhiyun char *new_unc;
4296*4882a593Smuzhiyun
4297*4882a593Smuzhiyun new_unc = kmalloc(len, GFP_KERNEL);
4298*4882a593Smuzhiyun if (!new_unc)
4299*4882a593Smuzhiyun return -ENOMEM;
4300*4882a593Smuzhiyun scnprintf(new_unc, len, "\\%s", tgt);
4301*4882a593Smuzhiyun
4302*4882a593Smuzhiyun kfree(vol->UNC);
4303*4882a593Smuzhiyun vol->UNC = new_unc;
4304*4882a593Smuzhiyun
4305*4882a593Smuzhiyun if (fake_vol->prepath) {
4306*4882a593Smuzhiyun kfree(vol->prepath);
4307*4882a593Smuzhiyun vol->prepath = fake_vol->prepath;
4308*4882a593Smuzhiyun fake_vol->prepath = NULL;
4309*4882a593Smuzhiyun }
4310*4882a593Smuzhiyun memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr));
4311*4882a593Smuzhiyun
4312*4882a593Smuzhiyun return 0;
4313*4882a593Smuzhiyun }
4314*4882a593Smuzhiyun
setup_dfs_tgt_conn(const char * path,const char * full_path,const struct dfs_cache_tgt_iterator * tgt_it,struct cifs_sb_info * cifs_sb,struct smb_vol * vol,unsigned int * xid,struct TCP_Server_Info ** server,struct cifs_ses ** ses,struct cifs_tcon ** tcon)4315*4882a593Smuzhiyun static int setup_dfs_tgt_conn(const char *path, const char *full_path,
4316*4882a593Smuzhiyun const struct dfs_cache_tgt_iterator *tgt_it,
4317*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb, struct smb_vol *vol, unsigned int *xid,
4318*4882a593Smuzhiyun struct TCP_Server_Info **server, struct cifs_ses **ses,
4319*4882a593Smuzhiyun struct cifs_tcon **tcon)
4320*4882a593Smuzhiyun {
4321*4882a593Smuzhiyun int rc;
4322*4882a593Smuzhiyun struct dfs_info3_param ref = {0};
4323*4882a593Smuzhiyun char *mdata = NULL, *fake_devname = NULL;
4324*4882a593Smuzhiyun struct smb_vol fake_vol = {NULL};
4325*4882a593Smuzhiyun
4326*4882a593Smuzhiyun cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
4327*4882a593Smuzhiyun
4328*4882a593Smuzhiyun rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
4329*4882a593Smuzhiyun if (rc)
4330*4882a593Smuzhiyun return rc;
4331*4882a593Smuzhiyun
4332*4882a593Smuzhiyun mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref, &fake_devname);
4333*4882a593Smuzhiyun free_dfs_info_param(&ref);
4334*4882a593Smuzhiyun
4335*4882a593Smuzhiyun if (IS_ERR(mdata)) {
4336*4882a593Smuzhiyun rc = PTR_ERR(mdata);
4337*4882a593Smuzhiyun mdata = NULL;
4338*4882a593Smuzhiyun } else {
4339*4882a593Smuzhiyun cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname);
4340*4882a593Smuzhiyun rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname,
4341*4882a593Smuzhiyun false);
4342*4882a593Smuzhiyun }
4343*4882a593Smuzhiyun kfree(mdata);
4344*4882a593Smuzhiyun kfree(fake_devname);
4345*4882a593Smuzhiyun
4346*4882a593Smuzhiyun if (!rc) {
4347*4882a593Smuzhiyun /*
4348*4882a593Smuzhiyun * We use a 'fake_vol' here because we need pass it down to the
4349*4882a593Smuzhiyun * mount_{get,put} functions to test connection against new DFS
4350*4882a593Smuzhiyun * targets.
4351*4882a593Smuzhiyun */
4352*4882a593Smuzhiyun mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
4353*4882a593Smuzhiyun rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses,
4354*4882a593Smuzhiyun tcon);
4355*4882a593Smuzhiyun if (!rc || (*server && *ses)) {
4356*4882a593Smuzhiyun /*
4357*4882a593Smuzhiyun * We were able to connect to new target server.
4358*4882a593Smuzhiyun * Update current volume info with new target server.
4359*4882a593Smuzhiyun */
4360*4882a593Smuzhiyun rc = update_vol_info(tgt_it, &fake_vol, vol);
4361*4882a593Smuzhiyun }
4362*4882a593Smuzhiyun }
4363*4882a593Smuzhiyun cifs_cleanup_volume_info_contents(&fake_vol);
4364*4882a593Smuzhiyun return rc;
4365*4882a593Smuzhiyun }
4366*4882a593Smuzhiyun
do_dfs_failover(const char * path,const char * full_path,struct cifs_sb_info * cifs_sb,struct smb_vol * vol,struct cifs_ses * root_ses,unsigned int * xid,struct TCP_Server_Info ** server,struct cifs_ses ** ses,struct cifs_tcon ** tcon)4367*4882a593Smuzhiyun static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
4368*4882a593Smuzhiyun struct smb_vol *vol, struct cifs_ses *root_ses, unsigned int *xid,
4369*4882a593Smuzhiyun struct TCP_Server_Info **server, struct cifs_ses **ses,
4370*4882a593Smuzhiyun struct cifs_tcon **tcon)
4371*4882a593Smuzhiyun {
4372*4882a593Smuzhiyun int rc;
4373*4882a593Smuzhiyun struct dfs_cache_tgt_list tgt_list;
4374*4882a593Smuzhiyun struct dfs_cache_tgt_iterator *tgt_it = NULL;
4375*4882a593Smuzhiyun
4376*4882a593Smuzhiyun if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
4377*4882a593Smuzhiyun return -EOPNOTSUPP;
4378*4882a593Smuzhiyun
4379*4882a593Smuzhiyun rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
4380*4882a593Smuzhiyun if (rc)
4381*4882a593Smuzhiyun return rc;
4382*4882a593Smuzhiyun
4383*4882a593Smuzhiyun for (;;) {
4384*4882a593Smuzhiyun /* Get next DFS target server - if any */
4385*4882a593Smuzhiyun rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
4386*4882a593Smuzhiyun if (rc)
4387*4882a593Smuzhiyun break;
4388*4882a593Smuzhiyun /* Connect to next DFS target */
4389*4882a593Smuzhiyun rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, vol, xid, server, ses,
4390*4882a593Smuzhiyun tcon);
4391*4882a593Smuzhiyun if (!rc || (*server && *ses))
4392*4882a593Smuzhiyun break;
4393*4882a593Smuzhiyun }
4394*4882a593Smuzhiyun if (!rc) {
4395*4882a593Smuzhiyun /*
4396*4882a593Smuzhiyun * Update DFS target hint in DFS referral cache with the target
4397*4882a593Smuzhiyun * server we successfully reconnected to.
4398*4882a593Smuzhiyun */
4399*4882a593Smuzhiyun rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
4400*4882a593Smuzhiyun cifs_sb->local_nls,
4401*4882a593Smuzhiyun cifs_remap(cifs_sb), path,
4402*4882a593Smuzhiyun tgt_it);
4403*4882a593Smuzhiyun }
4404*4882a593Smuzhiyun dfs_cache_free_tgts(&tgt_list);
4405*4882a593Smuzhiyun return rc;
4406*4882a593Smuzhiyun }
4407*4882a593Smuzhiyun #endif
4408*4882a593Smuzhiyun
4409*4882a593Smuzhiyun int
cifs_setup_volume_info(struct smb_vol * volume_info,char * mount_data,const char * devname,bool is_smb3)4410*4882a593Smuzhiyun cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
4411*4882a593Smuzhiyun const char *devname, bool is_smb3)
4412*4882a593Smuzhiyun {
4413*4882a593Smuzhiyun int rc = 0;
4414*4882a593Smuzhiyun
4415*4882a593Smuzhiyun if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3))
4416*4882a593Smuzhiyun return -EINVAL;
4417*4882a593Smuzhiyun
4418*4882a593Smuzhiyun if (volume_info->nullauth) {
4419*4882a593Smuzhiyun cifs_dbg(FYI, "Anonymous login\n");
4420*4882a593Smuzhiyun kfree(volume_info->username);
4421*4882a593Smuzhiyun volume_info->username = NULL;
4422*4882a593Smuzhiyun } else if (volume_info->username) {
4423*4882a593Smuzhiyun /* BB fixme parse for domain name here */
4424*4882a593Smuzhiyun cifs_dbg(FYI, "Username: %s\n", volume_info->username);
4425*4882a593Smuzhiyun } else {
4426*4882a593Smuzhiyun cifs_dbg(VFS, "No username specified\n");
4427*4882a593Smuzhiyun /* In userspace mount helper we can get user name from alternate
4428*4882a593Smuzhiyun locations such as env variables and files on disk */
4429*4882a593Smuzhiyun return -EINVAL;
4430*4882a593Smuzhiyun }
4431*4882a593Smuzhiyun
4432*4882a593Smuzhiyun /* this is needed for ASCII cp to Unicode converts */
4433*4882a593Smuzhiyun if (volume_info->iocharset == NULL) {
4434*4882a593Smuzhiyun /* load_nls_default cannot return null */
4435*4882a593Smuzhiyun volume_info->local_nls = load_nls_default();
4436*4882a593Smuzhiyun } else {
4437*4882a593Smuzhiyun volume_info->local_nls = load_nls(volume_info->iocharset);
4438*4882a593Smuzhiyun if (volume_info->local_nls == NULL) {
4439*4882a593Smuzhiyun cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n",
4440*4882a593Smuzhiyun volume_info->iocharset);
4441*4882a593Smuzhiyun return -ELIBACC;
4442*4882a593Smuzhiyun }
4443*4882a593Smuzhiyun }
4444*4882a593Smuzhiyun
4445*4882a593Smuzhiyun return rc;
4446*4882a593Smuzhiyun }
4447*4882a593Smuzhiyun
4448*4882a593Smuzhiyun struct smb_vol *
cifs_get_volume_info(char * mount_data,const char * devname,bool is_smb3)4449*4882a593Smuzhiyun cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3)
4450*4882a593Smuzhiyun {
4451*4882a593Smuzhiyun int rc;
4452*4882a593Smuzhiyun struct smb_vol *volume_info;
4453*4882a593Smuzhiyun
4454*4882a593Smuzhiyun volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL);
4455*4882a593Smuzhiyun if (!volume_info)
4456*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
4457*4882a593Smuzhiyun
4458*4882a593Smuzhiyun rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3);
4459*4882a593Smuzhiyun if (rc) {
4460*4882a593Smuzhiyun cifs_cleanup_volume_info(volume_info);
4461*4882a593Smuzhiyun volume_info = ERR_PTR(rc);
4462*4882a593Smuzhiyun }
4463*4882a593Smuzhiyun
4464*4882a593Smuzhiyun return volume_info;
4465*4882a593Smuzhiyun }
4466*4882a593Smuzhiyun
4467*4882a593Smuzhiyun static int
cifs_are_all_path_components_accessible(struct TCP_Server_Info * server,unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,char * full_path,int added_treename)4468*4882a593Smuzhiyun cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
4469*4882a593Smuzhiyun unsigned int xid,
4470*4882a593Smuzhiyun struct cifs_tcon *tcon,
4471*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb,
4472*4882a593Smuzhiyun char *full_path,
4473*4882a593Smuzhiyun int added_treename)
4474*4882a593Smuzhiyun {
4475*4882a593Smuzhiyun int rc;
4476*4882a593Smuzhiyun char *s;
4477*4882a593Smuzhiyun char sep, tmp;
4478*4882a593Smuzhiyun int skip = added_treename ? 1 : 0;
4479*4882a593Smuzhiyun
4480*4882a593Smuzhiyun sep = CIFS_DIR_SEP(cifs_sb);
4481*4882a593Smuzhiyun s = full_path;
4482*4882a593Smuzhiyun
4483*4882a593Smuzhiyun rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
4484*4882a593Smuzhiyun while (rc == 0) {
4485*4882a593Smuzhiyun /* skip separators */
4486*4882a593Smuzhiyun while (*s == sep)
4487*4882a593Smuzhiyun s++;
4488*4882a593Smuzhiyun if (!*s)
4489*4882a593Smuzhiyun break;
4490*4882a593Smuzhiyun /* next separator */
4491*4882a593Smuzhiyun while (*s && *s != sep)
4492*4882a593Smuzhiyun s++;
4493*4882a593Smuzhiyun /*
4494*4882a593Smuzhiyun * if the treename is added, we then have to skip the first
4495*4882a593Smuzhiyun * part within the separators
4496*4882a593Smuzhiyun */
4497*4882a593Smuzhiyun if (skip) {
4498*4882a593Smuzhiyun skip = 0;
4499*4882a593Smuzhiyun continue;
4500*4882a593Smuzhiyun }
4501*4882a593Smuzhiyun /*
4502*4882a593Smuzhiyun * temporarily null-terminate the path at the end of
4503*4882a593Smuzhiyun * the current component
4504*4882a593Smuzhiyun */
4505*4882a593Smuzhiyun tmp = *s;
4506*4882a593Smuzhiyun *s = 0;
4507*4882a593Smuzhiyun rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
4508*4882a593Smuzhiyun full_path);
4509*4882a593Smuzhiyun *s = tmp;
4510*4882a593Smuzhiyun }
4511*4882a593Smuzhiyun return rc;
4512*4882a593Smuzhiyun }
4513*4882a593Smuzhiyun
4514*4882a593Smuzhiyun /*
4515*4882a593Smuzhiyun * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
4516*4882a593Smuzhiyun * otherwise 0.
4517*4882a593Smuzhiyun */
is_path_remote(struct cifs_sb_info * cifs_sb,struct smb_vol * vol,const unsigned int xid,struct TCP_Server_Info * server,struct cifs_tcon * tcon)4518*4882a593Smuzhiyun static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
4519*4882a593Smuzhiyun const unsigned int xid,
4520*4882a593Smuzhiyun struct TCP_Server_Info *server,
4521*4882a593Smuzhiyun struct cifs_tcon *tcon)
4522*4882a593Smuzhiyun {
4523*4882a593Smuzhiyun int rc;
4524*4882a593Smuzhiyun char *full_path;
4525*4882a593Smuzhiyun
4526*4882a593Smuzhiyun if (!server->ops->is_path_accessible)
4527*4882a593Smuzhiyun return -EOPNOTSUPP;
4528*4882a593Smuzhiyun
4529*4882a593Smuzhiyun /*
4530*4882a593Smuzhiyun * cifs_build_path_to_root works only when we have a valid tcon
4531*4882a593Smuzhiyun */
4532*4882a593Smuzhiyun full_path = cifs_build_path_to_root(vol, cifs_sb, tcon,
4533*4882a593Smuzhiyun tcon->Flags & SMB_SHARE_IS_IN_DFS);
4534*4882a593Smuzhiyun if (full_path == NULL)
4535*4882a593Smuzhiyun return -ENOMEM;
4536*4882a593Smuzhiyun
4537*4882a593Smuzhiyun cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
4538*4882a593Smuzhiyun
4539*4882a593Smuzhiyun rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
4540*4882a593Smuzhiyun full_path);
4541*4882a593Smuzhiyun if (rc != 0 && rc != -EREMOTE) {
4542*4882a593Smuzhiyun kfree(full_path);
4543*4882a593Smuzhiyun return rc;
4544*4882a593Smuzhiyun }
4545*4882a593Smuzhiyun
4546*4882a593Smuzhiyun if (rc != -EREMOTE) {
4547*4882a593Smuzhiyun rc = cifs_are_all_path_components_accessible(server, xid, tcon,
4548*4882a593Smuzhiyun cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
4549*4882a593Smuzhiyun if (rc != 0) {
4550*4882a593Smuzhiyun cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
4551*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4552*4882a593Smuzhiyun rc = 0;
4553*4882a593Smuzhiyun }
4554*4882a593Smuzhiyun }
4555*4882a593Smuzhiyun
4556*4882a593Smuzhiyun kfree(full_path);
4557*4882a593Smuzhiyun return rc;
4558*4882a593Smuzhiyun }
4559*4882a593Smuzhiyun
4560*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
set_root_ses(struct cifs_sb_info * cifs_sb,struct cifs_ses * ses,struct cifs_ses ** root_ses)4561*4882a593Smuzhiyun static void set_root_ses(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
4562*4882a593Smuzhiyun struct cifs_ses **root_ses)
4563*4882a593Smuzhiyun {
4564*4882a593Smuzhiyun if (ses) {
4565*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
4566*4882a593Smuzhiyun ses->ses_count++;
4567*4882a593Smuzhiyun if (ses->tcon_ipc)
4568*4882a593Smuzhiyun ses->tcon_ipc->remap = cifs_remap(cifs_sb);
4569*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
4570*4882a593Smuzhiyun }
4571*4882a593Smuzhiyun *root_ses = ses;
4572*4882a593Smuzhiyun }
4573*4882a593Smuzhiyun
put_root_ses(struct cifs_ses * ses)4574*4882a593Smuzhiyun static void put_root_ses(struct cifs_ses *ses)
4575*4882a593Smuzhiyun {
4576*4882a593Smuzhiyun if (ses)
4577*4882a593Smuzhiyun cifs_put_smb_ses(ses);
4578*4882a593Smuzhiyun }
4579*4882a593Smuzhiyun
4580*4882a593Smuzhiyun /* Check if a path component is remote and then update @dfs_path accordingly */
check_dfs_prepath(struct cifs_sb_info * cifs_sb,struct smb_vol * vol,const unsigned int xid,struct TCP_Server_Info * server,struct cifs_tcon * tcon,char ** dfs_path)4581*4882a593Smuzhiyun static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
4582*4882a593Smuzhiyun const unsigned int xid, struct TCP_Server_Info *server,
4583*4882a593Smuzhiyun struct cifs_tcon *tcon, char **dfs_path)
4584*4882a593Smuzhiyun {
4585*4882a593Smuzhiyun char *path, *s;
4586*4882a593Smuzhiyun char sep = CIFS_DIR_SEP(cifs_sb), tmp;
4587*4882a593Smuzhiyun char *npath;
4588*4882a593Smuzhiyun int rc = 0;
4589*4882a593Smuzhiyun int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS;
4590*4882a593Smuzhiyun int skip = added_treename;
4591*4882a593Smuzhiyun
4592*4882a593Smuzhiyun path = cifs_build_path_to_root(vol, cifs_sb, tcon, added_treename);
4593*4882a593Smuzhiyun if (!path)
4594*4882a593Smuzhiyun return -ENOMEM;
4595*4882a593Smuzhiyun
4596*4882a593Smuzhiyun /*
4597*4882a593Smuzhiyun * Walk through the path components in @path and check if they're accessible. In case any of
4598*4882a593Smuzhiyun * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path
4599*4882a593Smuzhiyun * (NOT including the remaining components).
4600*4882a593Smuzhiyun */
4601*4882a593Smuzhiyun s = path;
4602*4882a593Smuzhiyun do {
4603*4882a593Smuzhiyun /* skip separators */
4604*4882a593Smuzhiyun while (*s && *s == sep)
4605*4882a593Smuzhiyun s++;
4606*4882a593Smuzhiyun if (!*s)
4607*4882a593Smuzhiyun break;
4608*4882a593Smuzhiyun /* next separator */
4609*4882a593Smuzhiyun while (*s && *s != sep)
4610*4882a593Smuzhiyun s++;
4611*4882a593Smuzhiyun /*
4612*4882a593Smuzhiyun * if the treename is added, we then have to skip the first
4613*4882a593Smuzhiyun * part within the separators
4614*4882a593Smuzhiyun */
4615*4882a593Smuzhiyun if (skip) {
4616*4882a593Smuzhiyun skip = 0;
4617*4882a593Smuzhiyun continue;
4618*4882a593Smuzhiyun }
4619*4882a593Smuzhiyun tmp = *s;
4620*4882a593Smuzhiyun *s = 0;
4621*4882a593Smuzhiyun rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path);
4622*4882a593Smuzhiyun if (rc && rc == -EREMOTE) {
4623*4882a593Smuzhiyun struct smb_vol v = {NULL};
4624*4882a593Smuzhiyun /* if @path contains a tree name, skip it in the prefix path */
4625*4882a593Smuzhiyun if (added_treename) {
4626*4882a593Smuzhiyun rc = cifs_parse_devname(path, &v);
4627*4882a593Smuzhiyun if (rc)
4628*4882a593Smuzhiyun break;
4629*4882a593Smuzhiyun rc = -EREMOTE;
4630*4882a593Smuzhiyun npath = build_unc_path_to_root(&v, cifs_sb, true);
4631*4882a593Smuzhiyun cifs_cleanup_volume_info_contents(&v);
4632*4882a593Smuzhiyun } else {
4633*4882a593Smuzhiyun v.UNC = vol->UNC;
4634*4882a593Smuzhiyun v.prepath = path + 1;
4635*4882a593Smuzhiyun npath = build_unc_path_to_root(&v, cifs_sb, true);
4636*4882a593Smuzhiyun }
4637*4882a593Smuzhiyun if (IS_ERR(npath)) {
4638*4882a593Smuzhiyun rc = PTR_ERR(npath);
4639*4882a593Smuzhiyun break;
4640*4882a593Smuzhiyun }
4641*4882a593Smuzhiyun kfree(*dfs_path);
4642*4882a593Smuzhiyun *dfs_path = npath;
4643*4882a593Smuzhiyun }
4644*4882a593Smuzhiyun *s = tmp;
4645*4882a593Smuzhiyun } while (rc == 0);
4646*4882a593Smuzhiyun
4647*4882a593Smuzhiyun kfree(path);
4648*4882a593Smuzhiyun return rc;
4649*4882a593Smuzhiyun }
4650*4882a593Smuzhiyun
cifs_mount(struct cifs_sb_info * cifs_sb,struct smb_vol * vol)4651*4882a593Smuzhiyun int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4652*4882a593Smuzhiyun {
4653*4882a593Smuzhiyun int rc = 0;
4654*4882a593Smuzhiyun unsigned int xid;
4655*4882a593Smuzhiyun struct TCP_Server_Info *server = NULL;
4656*4882a593Smuzhiyun struct cifs_ses *ses = NULL, *root_ses = NULL;
4657*4882a593Smuzhiyun struct cifs_tcon *tcon = NULL;
4658*4882a593Smuzhiyun int count = 0;
4659*4882a593Smuzhiyun char *ref_path = NULL, *full_path = NULL;
4660*4882a593Smuzhiyun char *oldmnt = NULL;
4661*4882a593Smuzhiyun char *mntdata = NULL;
4662*4882a593Smuzhiyun
4663*4882a593Smuzhiyun rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4664*4882a593Smuzhiyun /*
4665*4882a593Smuzhiyun * Unconditionally try to get an DFS referral (even cached) to determine whether it is an
4666*4882a593Smuzhiyun * DFS mount.
4667*4882a593Smuzhiyun *
4668*4882a593Smuzhiyun * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
4669*4882a593Smuzhiyun * to respond with PATH_NOT_COVERED to requests that include the prefix.
4670*4882a593Smuzhiyun */
4671*4882a593Smuzhiyun if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), vol->UNC + 1, NULL,
4672*4882a593Smuzhiyun NULL)) {
4673*4882a593Smuzhiyun /* No DFS referral was returned. Looks like a regular share. */
4674*4882a593Smuzhiyun if (rc)
4675*4882a593Smuzhiyun goto error;
4676*4882a593Smuzhiyun /* Check if it is fully accessible and then mount it */
4677*4882a593Smuzhiyun rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4678*4882a593Smuzhiyun if (!rc)
4679*4882a593Smuzhiyun goto out;
4680*4882a593Smuzhiyun if (rc != -EREMOTE)
4681*4882a593Smuzhiyun goto error;
4682*4882a593Smuzhiyun }
4683*4882a593Smuzhiyun /* Save mount options */
4684*4882a593Smuzhiyun mntdata = kstrndup(cifs_sb->mountdata, strlen(cifs_sb->mountdata), GFP_KERNEL);
4685*4882a593Smuzhiyun if (!mntdata) {
4686*4882a593Smuzhiyun rc = -ENOMEM;
4687*4882a593Smuzhiyun goto error;
4688*4882a593Smuzhiyun }
4689*4882a593Smuzhiyun /* Get path of DFS root */
4690*4882a593Smuzhiyun ref_path = build_unc_path_to_root(vol, cifs_sb, false);
4691*4882a593Smuzhiyun if (IS_ERR(ref_path)) {
4692*4882a593Smuzhiyun rc = PTR_ERR(ref_path);
4693*4882a593Smuzhiyun ref_path = NULL;
4694*4882a593Smuzhiyun goto error;
4695*4882a593Smuzhiyun }
4696*4882a593Smuzhiyun
4697*4882a593Smuzhiyun set_root_ses(cifs_sb, ses, &root_ses);
4698*4882a593Smuzhiyun do {
4699*4882a593Smuzhiyun /* Save full path of last DFS path we used to resolve final target server */
4700*4882a593Smuzhiyun kfree(full_path);
4701*4882a593Smuzhiyun full_path = build_unc_path_to_root(vol, cifs_sb, !!count);
4702*4882a593Smuzhiyun if (IS_ERR(full_path)) {
4703*4882a593Smuzhiyun rc = PTR_ERR(full_path);
4704*4882a593Smuzhiyun full_path = NULL;
4705*4882a593Smuzhiyun break;
4706*4882a593Smuzhiyun }
4707*4882a593Smuzhiyun /* Chase referral */
4708*4882a593Smuzhiyun oldmnt = cifs_sb->mountdata;
4709*4882a593Smuzhiyun rc = expand_dfs_referral(xid, root_ses, vol, cifs_sb, ref_path + 1);
4710*4882a593Smuzhiyun if (rc)
4711*4882a593Smuzhiyun break;
4712*4882a593Smuzhiyun /* Connect to new DFS target only if we were redirected */
4713*4882a593Smuzhiyun if (oldmnt != cifs_sb->mountdata) {
4714*4882a593Smuzhiyun mount_put_conns(cifs_sb, xid, server, ses, tcon);
4715*4882a593Smuzhiyun rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4716*4882a593Smuzhiyun }
4717*4882a593Smuzhiyun if (rc && !server && !ses) {
4718*4882a593Smuzhiyun /* Failed to connect. Try to connect to other targets in the referral. */
4719*4882a593Smuzhiyun rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, vol, root_ses, &xid,
4720*4882a593Smuzhiyun &server, &ses, &tcon);
4721*4882a593Smuzhiyun }
4722*4882a593Smuzhiyun if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses)
4723*4882a593Smuzhiyun break;
4724*4882a593Smuzhiyun if (!tcon)
4725*4882a593Smuzhiyun continue;
4726*4882a593Smuzhiyun /* Make sure that requests go through new root servers */
4727*4882a593Smuzhiyun if (is_tcon_dfs(tcon)) {
4728*4882a593Smuzhiyun put_root_ses(root_ses);
4729*4882a593Smuzhiyun set_root_ses(cifs_sb, ses, &root_ses);
4730*4882a593Smuzhiyun }
4731*4882a593Smuzhiyun /* Check for remaining path components and then continue chasing them (-EREMOTE) */
4732*4882a593Smuzhiyun rc = check_dfs_prepath(cifs_sb, vol, xid, server, tcon, &ref_path);
4733*4882a593Smuzhiyun /* Prevent recursion on broken link referrals */
4734*4882a593Smuzhiyun if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
4735*4882a593Smuzhiyun rc = -ELOOP;
4736*4882a593Smuzhiyun } while (rc == -EREMOTE);
4737*4882a593Smuzhiyun
4738*4882a593Smuzhiyun if (rc)
4739*4882a593Smuzhiyun goto error;
4740*4882a593Smuzhiyun put_root_ses(root_ses);
4741*4882a593Smuzhiyun root_ses = NULL;
4742*4882a593Smuzhiyun kfree(ref_path);
4743*4882a593Smuzhiyun ref_path = NULL;
4744*4882a593Smuzhiyun /*
4745*4882a593Smuzhiyun * Store DFS full path in both superblock and tree connect structures.
4746*4882a593Smuzhiyun *
4747*4882a593Smuzhiyun * For DFS root mounts, the prefix path (cifs_sb->prepath) is preserved during reconnect so
4748*4882a593Smuzhiyun * only the root path is set in cifs_sb->origin_fullpath and tcon->dfs_path. And for DFS
4749*4882a593Smuzhiyun * links, the prefix path is included in both and may be changed during reconnect. See
4750*4882a593Smuzhiyun * cifs_tree_connect().
4751*4882a593Smuzhiyun */
4752*4882a593Smuzhiyun cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL);
4753*4882a593Smuzhiyun if (!cifs_sb->origin_fullpath) {
4754*4882a593Smuzhiyun rc = -ENOMEM;
4755*4882a593Smuzhiyun goto error;
4756*4882a593Smuzhiyun }
4757*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
4758*4882a593Smuzhiyun tcon->dfs_path = full_path;
4759*4882a593Smuzhiyun full_path = NULL;
4760*4882a593Smuzhiyun tcon->remap = cifs_remap(cifs_sb);
4761*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
4762*4882a593Smuzhiyun
4763*4882a593Smuzhiyun /* Add original volume information for DFS cache to be used when refreshing referrals */
4764*4882a593Smuzhiyun rc = dfs_cache_add_vol(mntdata, vol, cifs_sb->origin_fullpath);
4765*4882a593Smuzhiyun if (rc)
4766*4882a593Smuzhiyun goto error;
4767*4882a593Smuzhiyun /*
4768*4882a593Smuzhiyun * After reconnecting to a different server, unique ids won't
4769*4882a593Smuzhiyun * match anymore, so we disable serverino. This prevents
4770*4882a593Smuzhiyun * dentry revalidation to think the dentry are stale (ESTALE).
4771*4882a593Smuzhiyun */
4772*4882a593Smuzhiyun cifs_autodisable_serverino(cifs_sb);
4773*4882a593Smuzhiyun /*
4774*4882a593Smuzhiyun * Force the use of prefix path to support failover on DFS paths that
4775*4882a593Smuzhiyun * resolve to targets that have different prefix paths.
4776*4882a593Smuzhiyun */
4777*4882a593Smuzhiyun cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4778*4882a593Smuzhiyun kfree(cifs_sb->prepath);
4779*4882a593Smuzhiyun cifs_sb->prepath = vol->prepath;
4780*4882a593Smuzhiyun vol->prepath = NULL;
4781*4882a593Smuzhiyun
4782*4882a593Smuzhiyun out:
4783*4882a593Smuzhiyun free_xid(xid);
4784*4882a593Smuzhiyun cifs_try_adding_channels(ses);
4785*4882a593Smuzhiyun return mount_setup_tlink(cifs_sb, ses, tcon);
4786*4882a593Smuzhiyun
4787*4882a593Smuzhiyun error:
4788*4882a593Smuzhiyun kfree(ref_path);
4789*4882a593Smuzhiyun kfree(full_path);
4790*4882a593Smuzhiyun kfree(mntdata);
4791*4882a593Smuzhiyun kfree(cifs_sb->origin_fullpath);
4792*4882a593Smuzhiyun put_root_ses(root_ses);
4793*4882a593Smuzhiyun mount_put_conns(cifs_sb, xid, server, ses, tcon);
4794*4882a593Smuzhiyun return rc;
4795*4882a593Smuzhiyun }
4796*4882a593Smuzhiyun #else
cifs_mount(struct cifs_sb_info * cifs_sb,struct smb_vol * vol)4797*4882a593Smuzhiyun int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4798*4882a593Smuzhiyun {
4799*4882a593Smuzhiyun int rc = 0;
4800*4882a593Smuzhiyun unsigned int xid;
4801*4882a593Smuzhiyun struct cifs_ses *ses;
4802*4882a593Smuzhiyun struct cifs_tcon *tcon;
4803*4882a593Smuzhiyun struct TCP_Server_Info *server;
4804*4882a593Smuzhiyun
4805*4882a593Smuzhiyun rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4806*4882a593Smuzhiyun if (rc)
4807*4882a593Smuzhiyun goto error;
4808*4882a593Smuzhiyun
4809*4882a593Smuzhiyun if (tcon) {
4810*4882a593Smuzhiyun rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4811*4882a593Smuzhiyun if (rc == -EREMOTE)
4812*4882a593Smuzhiyun rc = -EOPNOTSUPP;
4813*4882a593Smuzhiyun if (rc)
4814*4882a593Smuzhiyun goto error;
4815*4882a593Smuzhiyun }
4816*4882a593Smuzhiyun
4817*4882a593Smuzhiyun free_xid(xid);
4818*4882a593Smuzhiyun
4819*4882a593Smuzhiyun return mount_setup_tlink(cifs_sb, ses, tcon);
4820*4882a593Smuzhiyun
4821*4882a593Smuzhiyun error:
4822*4882a593Smuzhiyun mount_put_conns(cifs_sb, xid, server, ses, tcon);
4823*4882a593Smuzhiyun return rc;
4824*4882a593Smuzhiyun }
4825*4882a593Smuzhiyun #endif
4826*4882a593Smuzhiyun
4827*4882a593Smuzhiyun /*
4828*4882a593Smuzhiyun * Issue a TREE_CONNECT request.
4829*4882a593Smuzhiyun */
4830*4882a593Smuzhiyun int
CIFSTCon(const unsigned int xid,struct cifs_ses * ses,const char * tree,struct cifs_tcon * tcon,const struct nls_table * nls_codepage)4831*4882a593Smuzhiyun CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
4832*4882a593Smuzhiyun const char *tree, struct cifs_tcon *tcon,
4833*4882a593Smuzhiyun const struct nls_table *nls_codepage)
4834*4882a593Smuzhiyun {
4835*4882a593Smuzhiyun struct smb_hdr *smb_buffer;
4836*4882a593Smuzhiyun struct smb_hdr *smb_buffer_response;
4837*4882a593Smuzhiyun TCONX_REQ *pSMB;
4838*4882a593Smuzhiyun TCONX_RSP *pSMBr;
4839*4882a593Smuzhiyun unsigned char *bcc_ptr;
4840*4882a593Smuzhiyun int rc = 0;
4841*4882a593Smuzhiyun int length;
4842*4882a593Smuzhiyun __u16 bytes_left, count;
4843*4882a593Smuzhiyun
4844*4882a593Smuzhiyun if (ses == NULL)
4845*4882a593Smuzhiyun return -EIO;
4846*4882a593Smuzhiyun
4847*4882a593Smuzhiyun smb_buffer = cifs_buf_get();
4848*4882a593Smuzhiyun if (smb_buffer == NULL)
4849*4882a593Smuzhiyun return -ENOMEM;
4850*4882a593Smuzhiyun
4851*4882a593Smuzhiyun smb_buffer_response = smb_buffer;
4852*4882a593Smuzhiyun
4853*4882a593Smuzhiyun header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
4854*4882a593Smuzhiyun NULL /*no tid */ , 4 /*wct */ );
4855*4882a593Smuzhiyun
4856*4882a593Smuzhiyun smb_buffer->Mid = get_next_mid(ses->server);
4857*4882a593Smuzhiyun smb_buffer->Uid = ses->Suid;
4858*4882a593Smuzhiyun pSMB = (TCONX_REQ *) smb_buffer;
4859*4882a593Smuzhiyun pSMBr = (TCONX_RSP *) smb_buffer_response;
4860*4882a593Smuzhiyun
4861*4882a593Smuzhiyun pSMB->AndXCommand = 0xFF;
4862*4882a593Smuzhiyun pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
4863*4882a593Smuzhiyun bcc_ptr = &pSMB->Password[0];
4864*4882a593Smuzhiyun if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) {
4865*4882a593Smuzhiyun pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
4866*4882a593Smuzhiyun *bcc_ptr = 0; /* password is null byte */
4867*4882a593Smuzhiyun bcc_ptr++; /* skip password */
4868*4882a593Smuzhiyun /* already aligned so no need to do it below */
4869*4882a593Smuzhiyun } else {
4870*4882a593Smuzhiyun pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
4871*4882a593Smuzhiyun /* BB FIXME add code to fail this if NTLMv2 or Kerberos
4872*4882a593Smuzhiyun specified as required (when that support is added to
4873*4882a593Smuzhiyun the vfs in the future) as only NTLM or the much
4874*4882a593Smuzhiyun weaker LANMAN (which we do not send by default) is accepted
4875*4882a593Smuzhiyun by Samba (not sure whether other servers allow
4876*4882a593Smuzhiyun NTLMv2 password here) */
4877*4882a593Smuzhiyun #ifdef CONFIG_CIFS_WEAK_PW_HASH
4878*4882a593Smuzhiyun if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
4879*4882a593Smuzhiyun (ses->sectype == LANMAN))
4880*4882a593Smuzhiyun calc_lanman_hash(tcon->password, ses->server->cryptkey,
4881*4882a593Smuzhiyun ses->server->sec_mode &
4882*4882a593Smuzhiyun SECMODE_PW_ENCRYPT ? true : false,
4883*4882a593Smuzhiyun bcc_ptr);
4884*4882a593Smuzhiyun else
4885*4882a593Smuzhiyun #endif /* CIFS_WEAK_PW_HASH */
4886*4882a593Smuzhiyun rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
4887*4882a593Smuzhiyun bcc_ptr, nls_codepage);
4888*4882a593Smuzhiyun if (rc) {
4889*4882a593Smuzhiyun cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
4890*4882a593Smuzhiyun __func__, rc);
4891*4882a593Smuzhiyun cifs_buf_release(smb_buffer);
4892*4882a593Smuzhiyun return rc;
4893*4882a593Smuzhiyun }
4894*4882a593Smuzhiyun
4895*4882a593Smuzhiyun bcc_ptr += CIFS_AUTH_RESP_SIZE;
4896*4882a593Smuzhiyun if (ses->capabilities & CAP_UNICODE) {
4897*4882a593Smuzhiyun /* must align unicode strings */
4898*4882a593Smuzhiyun *bcc_ptr = 0; /* null byte password */
4899*4882a593Smuzhiyun bcc_ptr++;
4900*4882a593Smuzhiyun }
4901*4882a593Smuzhiyun }
4902*4882a593Smuzhiyun
4903*4882a593Smuzhiyun if (ses->server->sign)
4904*4882a593Smuzhiyun smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4905*4882a593Smuzhiyun
4906*4882a593Smuzhiyun if (ses->capabilities & CAP_STATUS32) {
4907*4882a593Smuzhiyun smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
4908*4882a593Smuzhiyun }
4909*4882a593Smuzhiyun if (ses->capabilities & CAP_DFS) {
4910*4882a593Smuzhiyun smb_buffer->Flags2 |= SMBFLG2_DFS;
4911*4882a593Smuzhiyun }
4912*4882a593Smuzhiyun if (ses->capabilities & CAP_UNICODE) {
4913*4882a593Smuzhiyun smb_buffer->Flags2 |= SMBFLG2_UNICODE;
4914*4882a593Smuzhiyun length =
4915*4882a593Smuzhiyun cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
4916*4882a593Smuzhiyun 6 /* max utf8 char length in bytes */ *
4917*4882a593Smuzhiyun (/* server len*/ + 256 /* share len */), nls_codepage);
4918*4882a593Smuzhiyun bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
4919*4882a593Smuzhiyun bcc_ptr += 2; /* skip trailing null */
4920*4882a593Smuzhiyun } else { /* ASCII */
4921*4882a593Smuzhiyun strcpy(bcc_ptr, tree);
4922*4882a593Smuzhiyun bcc_ptr += strlen(tree) + 1;
4923*4882a593Smuzhiyun }
4924*4882a593Smuzhiyun strcpy(bcc_ptr, "?????");
4925*4882a593Smuzhiyun bcc_ptr += strlen("?????");
4926*4882a593Smuzhiyun bcc_ptr += 1;
4927*4882a593Smuzhiyun count = bcc_ptr - &pSMB->Password[0];
4928*4882a593Smuzhiyun be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
4929*4882a593Smuzhiyun pSMB->ByteCount = cpu_to_le16(count);
4930*4882a593Smuzhiyun
4931*4882a593Smuzhiyun rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
4932*4882a593Smuzhiyun 0);
4933*4882a593Smuzhiyun
4934*4882a593Smuzhiyun /* above now done in SendReceive */
4935*4882a593Smuzhiyun if (rc == 0) {
4936*4882a593Smuzhiyun bool is_unicode;
4937*4882a593Smuzhiyun
4938*4882a593Smuzhiyun tcon->tidStatus = CifsGood;
4939*4882a593Smuzhiyun tcon->need_reconnect = false;
4940*4882a593Smuzhiyun tcon->tid = smb_buffer_response->Tid;
4941*4882a593Smuzhiyun bcc_ptr = pByteArea(smb_buffer_response);
4942*4882a593Smuzhiyun bytes_left = get_bcc(smb_buffer_response);
4943*4882a593Smuzhiyun length = strnlen(bcc_ptr, bytes_left - 2);
4944*4882a593Smuzhiyun if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
4945*4882a593Smuzhiyun is_unicode = true;
4946*4882a593Smuzhiyun else
4947*4882a593Smuzhiyun is_unicode = false;
4948*4882a593Smuzhiyun
4949*4882a593Smuzhiyun
4950*4882a593Smuzhiyun /* skip service field (NB: this field is always ASCII) */
4951*4882a593Smuzhiyun if (length == 3) {
4952*4882a593Smuzhiyun if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
4953*4882a593Smuzhiyun (bcc_ptr[2] == 'C')) {
4954*4882a593Smuzhiyun cifs_dbg(FYI, "IPC connection\n");
4955*4882a593Smuzhiyun tcon->ipc = true;
4956*4882a593Smuzhiyun tcon->pipe = true;
4957*4882a593Smuzhiyun }
4958*4882a593Smuzhiyun } else if (length == 2) {
4959*4882a593Smuzhiyun if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
4960*4882a593Smuzhiyun /* the most common case */
4961*4882a593Smuzhiyun cifs_dbg(FYI, "disk share connection\n");
4962*4882a593Smuzhiyun }
4963*4882a593Smuzhiyun }
4964*4882a593Smuzhiyun bcc_ptr += length + 1;
4965*4882a593Smuzhiyun bytes_left -= (length + 1);
4966*4882a593Smuzhiyun strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
4967*4882a593Smuzhiyun
4968*4882a593Smuzhiyun /* mostly informational -- no need to fail on error here */
4969*4882a593Smuzhiyun kfree(tcon->nativeFileSystem);
4970*4882a593Smuzhiyun tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
4971*4882a593Smuzhiyun bytes_left, is_unicode,
4972*4882a593Smuzhiyun nls_codepage);
4973*4882a593Smuzhiyun
4974*4882a593Smuzhiyun cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
4975*4882a593Smuzhiyun
4976*4882a593Smuzhiyun if ((smb_buffer_response->WordCount == 3) ||
4977*4882a593Smuzhiyun (smb_buffer_response->WordCount == 7))
4978*4882a593Smuzhiyun /* field is in same location */
4979*4882a593Smuzhiyun tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
4980*4882a593Smuzhiyun else
4981*4882a593Smuzhiyun tcon->Flags = 0;
4982*4882a593Smuzhiyun cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
4983*4882a593Smuzhiyun }
4984*4882a593Smuzhiyun
4985*4882a593Smuzhiyun cifs_buf_release(smb_buffer);
4986*4882a593Smuzhiyun return rc;
4987*4882a593Smuzhiyun }
4988*4882a593Smuzhiyun
delayed_free(struct rcu_head * p)4989*4882a593Smuzhiyun static void delayed_free(struct rcu_head *p)
4990*4882a593Smuzhiyun {
4991*4882a593Smuzhiyun struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu);
4992*4882a593Smuzhiyun unload_nls(sbi->local_nls);
4993*4882a593Smuzhiyun kfree(sbi);
4994*4882a593Smuzhiyun }
4995*4882a593Smuzhiyun
4996*4882a593Smuzhiyun void
cifs_umount(struct cifs_sb_info * cifs_sb)4997*4882a593Smuzhiyun cifs_umount(struct cifs_sb_info *cifs_sb)
4998*4882a593Smuzhiyun {
4999*4882a593Smuzhiyun struct rb_root *root = &cifs_sb->tlink_tree;
5000*4882a593Smuzhiyun struct rb_node *node;
5001*4882a593Smuzhiyun struct tcon_link *tlink;
5002*4882a593Smuzhiyun
5003*4882a593Smuzhiyun cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
5004*4882a593Smuzhiyun
5005*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5006*4882a593Smuzhiyun while ((node = rb_first(root))) {
5007*4882a593Smuzhiyun tlink = rb_entry(node, struct tcon_link, tl_rbnode);
5008*4882a593Smuzhiyun cifs_get_tlink(tlink);
5009*4882a593Smuzhiyun clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
5010*4882a593Smuzhiyun rb_erase(node, root);
5011*4882a593Smuzhiyun
5012*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5013*4882a593Smuzhiyun cifs_put_tlink(tlink);
5014*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5015*4882a593Smuzhiyun }
5016*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5017*4882a593Smuzhiyun
5018*4882a593Smuzhiyun kfree(cifs_sb->mountdata);
5019*4882a593Smuzhiyun kfree(cifs_sb->prepath);
5020*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
5021*4882a593Smuzhiyun dfs_cache_del_vol(cifs_sb->origin_fullpath);
5022*4882a593Smuzhiyun kfree(cifs_sb->origin_fullpath);
5023*4882a593Smuzhiyun #endif
5024*4882a593Smuzhiyun call_rcu(&cifs_sb->rcu, delayed_free);
5025*4882a593Smuzhiyun }
5026*4882a593Smuzhiyun
5027*4882a593Smuzhiyun int
cifs_negotiate_protocol(const unsigned int xid,struct cifs_ses * ses)5028*4882a593Smuzhiyun cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
5029*4882a593Smuzhiyun {
5030*4882a593Smuzhiyun int rc = 0;
5031*4882a593Smuzhiyun struct TCP_Server_Info *server = cifs_ses_server(ses);
5032*4882a593Smuzhiyun
5033*4882a593Smuzhiyun if (!server->ops->need_neg || !server->ops->negotiate)
5034*4882a593Smuzhiyun return -ENOSYS;
5035*4882a593Smuzhiyun
5036*4882a593Smuzhiyun /* only send once per connect */
5037*4882a593Smuzhiyun if (!server->ops->need_neg(server))
5038*4882a593Smuzhiyun return 0;
5039*4882a593Smuzhiyun
5040*4882a593Smuzhiyun rc = server->ops->negotiate(xid, ses);
5041*4882a593Smuzhiyun if (rc == 0) {
5042*4882a593Smuzhiyun spin_lock(&GlobalMid_Lock);
5043*4882a593Smuzhiyun if (server->tcpStatus == CifsNeedNegotiate)
5044*4882a593Smuzhiyun server->tcpStatus = CifsGood;
5045*4882a593Smuzhiyun else
5046*4882a593Smuzhiyun rc = -EHOSTDOWN;
5047*4882a593Smuzhiyun spin_unlock(&GlobalMid_Lock);
5048*4882a593Smuzhiyun }
5049*4882a593Smuzhiyun
5050*4882a593Smuzhiyun return rc;
5051*4882a593Smuzhiyun }
5052*4882a593Smuzhiyun
5053*4882a593Smuzhiyun int
cifs_setup_session(const unsigned int xid,struct cifs_ses * ses,struct nls_table * nls_info)5054*4882a593Smuzhiyun cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
5055*4882a593Smuzhiyun struct nls_table *nls_info)
5056*4882a593Smuzhiyun {
5057*4882a593Smuzhiyun int rc = -ENOSYS;
5058*4882a593Smuzhiyun struct TCP_Server_Info *server = cifs_ses_server(ses);
5059*4882a593Smuzhiyun
5060*4882a593Smuzhiyun if (!ses->binding) {
5061*4882a593Smuzhiyun ses->capabilities = server->capabilities;
5062*4882a593Smuzhiyun if (linuxExtEnabled == 0)
5063*4882a593Smuzhiyun ses->capabilities &= (~server->vals->cap_unix);
5064*4882a593Smuzhiyun
5065*4882a593Smuzhiyun if (ses->auth_key.response) {
5066*4882a593Smuzhiyun cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
5067*4882a593Smuzhiyun ses->auth_key.response);
5068*4882a593Smuzhiyun kfree(ses->auth_key.response);
5069*4882a593Smuzhiyun ses->auth_key.response = NULL;
5070*4882a593Smuzhiyun ses->auth_key.len = 0;
5071*4882a593Smuzhiyun }
5072*4882a593Smuzhiyun }
5073*4882a593Smuzhiyun
5074*4882a593Smuzhiyun cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
5075*4882a593Smuzhiyun server->sec_mode, server->capabilities, server->timeAdj);
5076*4882a593Smuzhiyun
5077*4882a593Smuzhiyun if (server->ops->sess_setup)
5078*4882a593Smuzhiyun rc = server->ops->sess_setup(xid, ses, nls_info);
5079*4882a593Smuzhiyun
5080*4882a593Smuzhiyun if (rc)
5081*4882a593Smuzhiyun cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
5082*4882a593Smuzhiyun
5083*4882a593Smuzhiyun return rc;
5084*4882a593Smuzhiyun }
5085*4882a593Smuzhiyun
5086*4882a593Smuzhiyun static int
cifs_set_vol_auth(struct smb_vol * vol,struct cifs_ses * ses)5087*4882a593Smuzhiyun cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
5088*4882a593Smuzhiyun {
5089*4882a593Smuzhiyun vol->sectype = ses->sectype;
5090*4882a593Smuzhiyun
5091*4882a593Smuzhiyun /* krb5 is special, since we don't need username or pw */
5092*4882a593Smuzhiyun if (vol->sectype == Kerberos)
5093*4882a593Smuzhiyun return 0;
5094*4882a593Smuzhiyun
5095*4882a593Smuzhiyun return cifs_set_cifscreds(vol, ses);
5096*4882a593Smuzhiyun }
5097*4882a593Smuzhiyun
5098*4882a593Smuzhiyun static struct cifs_tcon *
cifs_construct_tcon(struct cifs_sb_info * cifs_sb,kuid_t fsuid)5099*4882a593Smuzhiyun cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
5100*4882a593Smuzhiyun {
5101*4882a593Smuzhiyun int rc;
5102*4882a593Smuzhiyun struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
5103*4882a593Smuzhiyun struct cifs_ses *ses;
5104*4882a593Smuzhiyun struct cifs_tcon *tcon = NULL;
5105*4882a593Smuzhiyun struct smb_vol *vol_info;
5106*4882a593Smuzhiyun
5107*4882a593Smuzhiyun vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
5108*4882a593Smuzhiyun if (vol_info == NULL)
5109*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
5110*4882a593Smuzhiyun
5111*4882a593Smuzhiyun vol_info->local_nls = cifs_sb->local_nls;
5112*4882a593Smuzhiyun vol_info->linux_uid = fsuid;
5113*4882a593Smuzhiyun vol_info->cred_uid = fsuid;
5114*4882a593Smuzhiyun vol_info->UNC = master_tcon->treeName;
5115*4882a593Smuzhiyun vol_info->retry = master_tcon->retry;
5116*4882a593Smuzhiyun vol_info->nocase = master_tcon->nocase;
5117*4882a593Smuzhiyun vol_info->nohandlecache = master_tcon->nohandlecache;
5118*4882a593Smuzhiyun vol_info->local_lease = master_tcon->local_lease;
5119*4882a593Smuzhiyun vol_info->no_lease = master_tcon->no_lease;
5120*4882a593Smuzhiyun vol_info->resilient = master_tcon->use_resilient;
5121*4882a593Smuzhiyun vol_info->persistent = master_tcon->use_persistent;
5122*4882a593Smuzhiyun vol_info->handle_timeout = master_tcon->handle_timeout;
5123*4882a593Smuzhiyun vol_info->no_linux_ext = !master_tcon->unix_ext;
5124*4882a593Smuzhiyun vol_info->linux_ext = master_tcon->posix_extensions;
5125*4882a593Smuzhiyun vol_info->sectype = master_tcon->ses->sectype;
5126*4882a593Smuzhiyun vol_info->sign = master_tcon->ses->sign;
5127*4882a593Smuzhiyun vol_info->seal = master_tcon->seal;
5128*4882a593Smuzhiyun
5129*4882a593Smuzhiyun rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
5130*4882a593Smuzhiyun if (rc) {
5131*4882a593Smuzhiyun tcon = ERR_PTR(rc);
5132*4882a593Smuzhiyun goto out;
5133*4882a593Smuzhiyun }
5134*4882a593Smuzhiyun
5135*4882a593Smuzhiyun /* get a reference for the same TCP session */
5136*4882a593Smuzhiyun spin_lock(&cifs_tcp_ses_lock);
5137*4882a593Smuzhiyun ++master_tcon->ses->server->srv_count;
5138*4882a593Smuzhiyun spin_unlock(&cifs_tcp_ses_lock);
5139*4882a593Smuzhiyun
5140*4882a593Smuzhiyun ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
5141*4882a593Smuzhiyun if (IS_ERR(ses)) {
5142*4882a593Smuzhiyun tcon = (struct cifs_tcon *)ses;
5143*4882a593Smuzhiyun cifs_put_tcp_session(master_tcon->ses->server, 0);
5144*4882a593Smuzhiyun goto out;
5145*4882a593Smuzhiyun }
5146*4882a593Smuzhiyun
5147*4882a593Smuzhiyun tcon = cifs_get_tcon(ses, vol_info);
5148*4882a593Smuzhiyun if (IS_ERR(tcon)) {
5149*4882a593Smuzhiyun cifs_put_smb_ses(ses);
5150*4882a593Smuzhiyun goto out;
5151*4882a593Smuzhiyun }
5152*4882a593Smuzhiyun
5153*4882a593Smuzhiyun if (cap_unix(ses))
5154*4882a593Smuzhiyun reset_cifs_unix_caps(0, tcon, NULL, vol_info);
5155*4882a593Smuzhiyun
5156*4882a593Smuzhiyun out:
5157*4882a593Smuzhiyun kfree(vol_info->username);
5158*4882a593Smuzhiyun kfree_sensitive(vol_info->password);
5159*4882a593Smuzhiyun kfree(vol_info);
5160*4882a593Smuzhiyun
5161*4882a593Smuzhiyun return tcon;
5162*4882a593Smuzhiyun }
5163*4882a593Smuzhiyun
5164*4882a593Smuzhiyun struct cifs_tcon *
cifs_sb_master_tcon(struct cifs_sb_info * cifs_sb)5165*4882a593Smuzhiyun cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
5166*4882a593Smuzhiyun {
5167*4882a593Smuzhiyun return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
5168*4882a593Smuzhiyun }
5169*4882a593Smuzhiyun
5170*4882a593Smuzhiyun /* find and return a tlink with given uid */
5171*4882a593Smuzhiyun static struct tcon_link *
tlink_rb_search(struct rb_root * root,kuid_t uid)5172*4882a593Smuzhiyun tlink_rb_search(struct rb_root *root, kuid_t uid)
5173*4882a593Smuzhiyun {
5174*4882a593Smuzhiyun struct rb_node *node = root->rb_node;
5175*4882a593Smuzhiyun struct tcon_link *tlink;
5176*4882a593Smuzhiyun
5177*4882a593Smuzhiyun while (node) {
5178*4882a593Smuzhiyun tlink = rb_entry(node, struct tcon_link, tl_rbnode);
5179*4882a593Smuzhiyun
5180*4882a593Smuzhiyun if (uid_gt(tlink->tl_uid, uid))
5181*4882a593Smuzhiyun node = node->rb_left;
5182*4882a593Smuzhiyun else if (uid_lt(tlink->tl_uid, uid))
5183*4882a593Smuzhiyun node = node->rb_right;
5184*4882a593Smuzhiyun else
5185*4882a593Smuzhiyun return tlink;
5186*4882a593Smuzhiyun }
5187*4882a593Smuzhiyun return NULL;
5188*4882a593Smuzhiyun }
5189*4882a593Smuzhiyun
5190*4882a593Smuzhiyun /* insert a tcon_link into the tree */
5191*4882a593Smuzhiyun static void
tlink_rb_insert(struct rb_root * root,struct tcon_link * new_tlink)5192*4882a593Smuzhiyun tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
5193*4882a593Smuzhiyun {
5194*4882a593Smuzhiyun struct rb_node **new = &(root->rb_node), *parent = NULL;
5195*4882a593Smuzhiyun struct tcon_link *tlink;
5196*4882a593Smuzhiyun
5197*4882a593Smuzhiyun while (*new) {
5198*4882a593Smuzhiyun tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
5199*4882a593Smuzhiyun parent = *new;
5200*4882a593Smuzhiyun
5201*4882a593Smuzhiyun if (uid_gt(tlink->tl_uid, new_tlink->tl_uid))
5202*4882a593Smuzhiyun new = &((*new)->rb_left);
5203*4882a593Smuzhiyun else
5204*4882a593Smuzhiyun new = &((*new)->rb_right);
5205*4882a593Smuzhiyun }
5206*4882a593Smuzhiyun
5207*4882a593Smuzhiyun rb_link_node(&new_tlink->tl_rbnode, parent, new);
5208*4882a593Smuzhiyun rb_insert_color(&new_tlink->tl_rbnode, root);
5209*4882a593Smuzhiyun }
5210*4882a593Smuzhiyun
5211*4882a593Smuzhiyun /*
5212*4882a593Smuzhiyun * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
5213*4882a593Smuzhiyun * current task.
5214*4882a593Smuzhiyun *
5215*4882a593Smuzhiyun * If the superblock doesn't refer to a multiuser mount, then just return
5216*4882a593Smuzhiyun * the master tcon for the mount.
5217*4882a593Smuzhiyun *
5218*4882a593Smuzhiyun * First, search the rbtree for an existing tcon for this fsuid. If one
5219*4882a593Smuzhiyun * exists, then check to see if it's pending construction. If it is then wait
5220*4882a593Smuzhiyun * for construction to complete. Once it's no longer pending, check to see if
5221*4882a593Smuzhiyun * it failed and either return an error or retry construction, depending on
5222*4882a593Smuzhiyun * the timeout.
5223*4882a593Smuzhiyun *
5224*4882a593Smuzhiyun * If one doesn't exist then insert a new tcon_link struct into the tree and
5225*4882a593Smuzhiyun * try to construct a new one.
5226*4882a593Smuzhiyun */
5227*4882a593Smuzhiyun struct tcon_link *
cifs_sb_tlink(struct cifs_sb_info * cifs_sb)5228*4882a593Smuzhiyun cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
5229*4882a593Smuzhiyun {
5230*4882a593Smuzhiyun int ret;
5231*4882a593Smuzhiyun kuid_t fsuid = current_fsuid();
5232*4882a593Smuzhiyun struct tcon_link *tlink, *newtlink;
5233*4882a593Smuzhiyun
5234*4882a593Smuzhiyun if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
5235*4882a593Smuzhiyun return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
5236*4882a593Smuzhiyun
5237*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5238*4882a593Smuzhiyun tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
5239*4882a593Smuzhiyun if (tlink)
5240*4882a593Smuzhiyun cifs_get_tlink(tlink);
5241*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5242*4882a593Smuzhiyun
5243*4882a593Smuzhiyun if (tlink == NULL) {
5244*4882a593Smuzhiyun newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
5245*4882a593Smuzhiyun if (newtlink == NULL)
5246*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
5247*4882a593Smuzhiyun newtlink->tl_uid = fsuid;
5248*4882a593Smuzhiyun newtlink->tl_tcon = ERR_PTR(-EACCES);
5249*4882a593Smuzhiyun set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
5250*4882a593Smuzhiyun set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
5251*4882a593Smuzhiyun cifs_get_tlink(newtlink);
5252*4882a593Smuzhiyun
5253*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5254*4882a593Smuzhiyun /* was one inserted after previous search? */
5255*4882a593Smuzhiyun tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
5256*4882a593Smuzhiyun if (tlink) {
5257*4882a593Smuzhiyun cifs_get_tlink(tlink);
5258*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5259*4882a593Smuzhiyun kfree(newtlink);
5260*4882a593Smuzhiyun goto wait_for_construction;
5261*4882a593Smuzhiyun }
5262*4882a593Smuzhiyun tlink = newtlink;
5263*4882a593Smuzhiyun tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
5264*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5265*4882a593Smuzhiyun } else {
5266*4882a593Smuzhiyun wait_for_construction:
5267*4882a593Smuzhiyun ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
5268*4882a593Smuzhiyun TASK_INTERRUPTIBLE);
5269*4882a593Smuzhiyun if (ret) {
5270*4882a593Smuzhiyun cifs_put_tlink(tlink);
5271*4882a593Smuzhiyun return ERR_PTR(-ERESTARTSYS);
5272*4882a593Smuzhiyun }
5273*4882a593Smuzhiyun
5274*4882a593Smuzhiyun /* if it's good, return it */
5275*4882a593Smuzhiyun if (!IS_ERR(tlink->tl_tcon))
5276*4882a593Smuzhiyun return tlink;
5277*4882a593Smuzhiyun
5278*4882a593Smuzhiyun /* return error if we tried this already recently */
5279*4882a593Smuzhiyun if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
5280*4882a593Smuzhiyun cifs_put_tlink(tlink);
5281*4882a593Smuzhiyun return ERR_PTR(-EACCES);
5282*4882a593Smuzhiyun }
5283*4882a593Smuzhiyun
5284*4882a593Smuzhiyun if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
5285*4882a593Smuzhiyun goto wait_for_construction;
5286*4882a593Smuzhiyun }
5287*4882a593Smuzhiyun
5288*4882a593Smuzhiyun tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
5289*4882a593Smuzhiyun clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
5290*4882a593Smuzhiyun wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
5291*4882a593Smuzhiyun
5292*4882a593Smuzhiyun if (IS_ERR(tlink->tl_tcon)) {
5293*4882a593Smuzhiyun cifs_put_tlink(tlink);
5294*4882a593Smuzhiyun return ERR_PTR(-EACCES);
5295*4882a593Smuzhiyun }
5296*4882a593Smuzhiyun
5297*4882a593Smuzhiyun return tlink;
5298*4882a593Smuzhiyun }
5299*4882a593Smuzhiyun
5300*4882a593Smuzhiyun /*
5301*4882a593Smuzhiyun * periodic workqueue job that scans tcon_tree for a superblock and closes
5302*4882a593Smuzhiyun * out tcons.
5303*4882a593Smuzhiyun */
5304*4882a593Smuzhiyun static void
cifs_prune_tlinks(struct work_struct * work)5305*4882a593Smuzhiyun cifs_prune_tlinks(struct work_struct *work)
5306*4882a593Smuzhiyun {
5307*4882a593Smuzhiyun struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
5308*4882a593Smuzhiyun prune_tlinks.work);
5309*4882a593Smuzhiyun struct rb_root *root = &cifs_sb->tlink_tree;
5310*4882a593Smuzhiyun struct rb_node *node;
5311*4882a593Smuzhiyun struct rb_node *tmp;
5312*4882a593Smuzhiyun struct tcon_link *tlink;
5313*4882a593Smuzhiyun
5314*4882a593Smuzhiyun /*
5315*4882a593Smuzhiyun * Because we drop the spinlock in the loop in order to put the tlink
5316*4882a593Smuzhiyun * it's not guarded against removal of links from the tree. The only
5317*4882a593Smuzhiyun * places that remove entries from the tree are this function and
5318*4882a593Smuzhiyun * umounts. Because this function is non-reentrant and is canceled
5319*4882a593Smuzhiyun * before umount can proceed, this is safe.
5320*4882a593Smuzhiyun */
5321*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5322*4882a593Smuzhiyun node = rb_first(root);
5323*4882a593Smuzhiyun while (node != NULL) {
5324*4882a593Smuzhiyun tmp = node;
5325*4882a593Smuzhiyun node = rb_next(tmp);
5326*4882a593Smuzhiyun tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
5327*4882a593Smuzhiyun
5328*4882a593Smuzhiyun if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
5329*4882a593Smuzhiyun atomic_read(&tlink->tl_count) != 0 ||
5330*4882a593Smuzhiyun time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
5331*4882a593Smuzhiyun continue;
5332*4882a593Smuzhiyun
5333*4882a593Smuzhiyun cifs_get_tlink(tlink);
5334*4882a593Smuzhiyun clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
5335*4882a593Smuzhiyun rb_erase(tmp, root);
5336*4882a593Smuzhiyun
5337*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5338*4882a593Smuzhiyun cifs_put_tlink(tlink);
5339*4882a593Smuzhiyun spin_lock(&cifs_sb->tlink_tree_lock);
5340*4882a593Smuzhiyun }
5341*4882a593Smuzhiyun spin_unlock(&cifs_sb->tlink_tree_lock);
5342*4882a593Smuzhiyun
5343*4882a593Smuzhiyun queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
5344*4882a593Smuzhiyun TLINK_IDLE_EXPIRE);
5345*4882a593Smuzhiyun }
5346*4882a593Smuzhiyun
5347*4882a593Smuzhiyun #ifdef CONFIG_CIFS_DFS_UPCALL
cifs_tree_connect(const unsigned int xid,struct cifs_tcon * tcon,const struct nls_table * nlsc)5348*4882a593Smuzhiyun int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
5349*4882a593Smuzhiyun {
5350*4882a593Smuzhiyun int rc;
5351*4882a593Smuzhiyun struct TCP_Server_Info *server = tcon->ses->server;
5352*4882a593Smuzhiyun const struct smb_version_operations *ops = server->ops;
5353*4882a593Smuzhiyun struct dfs_cache_tgt_list tl;
5354*4882a593Smuzhiyun struct dfs_cache_tgt_iterator *it = NULL;
5355*4882a593Smuzhiyun char *tree;
5356*4882a593Smuzhiyun const char *tcp_host;
5357*4882a593Smuzhiyun size_t tcp_host_len;
5358*4882a593Smuzhiyun const char *dfs_host;
5359*4882a593Smuzhiyun size_t dfs_host_len;
5360*4882a593Smuzhiyun char *share = NULL, *prefix = NULL;
5361*4882a593Smuzhiyun struct dfs_info3_param ref = {0};
5362*4882a593Smuzhiyun bool isroot;
5363*4882a593Smuzhiyun
5364*4882a593Smuzhiyun tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
5365*4882a593Smuzhiyun if (!tree)
5366*4882a593Smuzhiyun return -ENOMEM;
5367*4882a593Smuzhiyun
5368*4882a593Smuzhiyun /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */
5369*4882a593Smuzhiyun if (!tcon->dfs_path || dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl)) {
5370*4882a593Smuzhiyun if (tcon->ipc) {
5371*4882a593Smuzhiyun scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
5372*4882a593Smuzhiyun rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5373*4882a593Smuzhiyun } else {
5374*4882a593Smuzhiyun rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
5375*4882a593Smuzhiyun }
5376*4882a593Smuzhiyun goto out;
5377*4882a593Smuzhiyun }
5378*4882a593Smuzhiyun
5379*4882a593Smuzhiyun isroot = ref.server_type == DFS_TYPE_ROOT;
5380*4882a593Smuzhiyun free_dfs_info_param(&ref);
5381*4882a593Smuzhiyun
5382*4882a593Smuzhiyun extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
5383*4882a593Smuzhiyun
5384*4882a593Smuzhiyun for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
5385*4882a593Smuzhiyun bool target_match;
5386*4882a593Smuzhiyun
5387*4882a593Smuzhiyun kfree(share);
5388*4882a593Smuzhiyun kfree(prefix);
5389*4882a593Smuzhiyun share = NULL;
5390*4882a593Smuzhiyun prefix = NULL;
5391*4882a593Smuzhiyun
5392*4882a593Smuzhiyun rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
5393*4882a593Smuzhiyun if (rc) {
5394*4882a593Smuzhiyun cifs_dbg(VFS, "%s: failed to parse target share %d\n",
5395*4882a593Smuzhiyun __func__, rc);
5396*4882a593Smuzhiyun continue;
5397*4882a593Smuzhiyun }
5398*4882a593Smuzhiyun
5399*4882a593Smuzhiyun extract_unc_hostname(share, &dfs_host, &dfs_host_len);
5400*4882a593Smuzhiyun
5401*4882a593Smuzhiyun if (dfs_host_len != tcp_host_len
5402*4882a593Smuzhiyun || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
5403*4882a593Smuzhiyun cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
5404*4882a593Smuzhiyun dfs_host, (int)tcp_host_len, tcp_host);
5405*4882a593Smuzhiyun
5406*4882a593Smuzhiyun rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
5407*4882a593Smuzhiyun if (rc) {
5408*4882a593Smuzhiyun cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc);
5409*4882a593Smuzhiyun break;
5410*4882a593Smuzhiyun }
5411*4882a593Smuzhiyun
5412*4882a593Smuzhiyun if (!target_match) {
5413*4882a593Smuzhiyun cifs_dbg(FYI, "%s: skipping target\n", __func__);
5414*4882a593Smuzhiyun continue;
5415*4882a593Smuzhiyun }
5416*4882a593Smuzhiyun }
5417*4882a593Smuzhiyun
5418*4882a593Smuzhiyun if (tcon->ipc) {
5419*4882a593Smuzhiyun scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
5420*4882a593Smuzhiyun rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5421*4882a593Smuzhiyun } else {
5422*4882a593Smuzhiyun scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
5423*4882a593Smuzhiyun rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5424*4882a593Smuzhiyun /* Only handle prefix paths of DFS link targets */
5425*4882a593Smuzhiyun if (!rc && !isroot) {
5426*4882a593Smuzhiyun rc = update_super_prepath(tcon, prefix);
5427*4882a593Smuzhiyun break;
5428*4882a593Smuzhiyun }
5429*4882a593Smuzhiyun }
5430*4882a593Smuzhiyun if (rc == -EREMOTE)
5431*4882a593Smuzhiyun break;
5432*4882a593Smuzhiyun }
5433*4882a593Smuzhiyun
5434*4882a593Smuzhiyun kfree(share);
5435*4882a593Smuzhiyun kfree(prefix);
5436*4882a593Smuzhiyun
5437*4882a593Smuzhiyun if (!rc) {
5438*4882a593Smuzhiyun if (it)
5439*4882a593Smuzhiyun rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
5440*4882a593Smuzhiyun else
5441*4882a593Smuzhiyun rc = -ENOENT;
5442*4882a593Smuzhiyun }
5443*4882a593Smuzhiyun dfs_cache_free_tgts(&tl);
5444*4882a593Smuzhiyun out:
5445*4882a593Smuzhiyun kfree(tree);
5446*4882a593Smuzhiyun return rc;
5447*4882a593Smuzhiyun }
5448*4882a593Smuzhiyun #else
cifs_tree_connect(const unsigned int xid,struct cifs_tcon * tcon,const struct nls_table * nlsc)5449*4882a593Smuzhiyun int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
5450*4882a593Smuzhiyun {
5451*4882a593Smuzhiyun const struct smb_version_operations *ops = tcon->ses->server->ops;
5452*4882a593Smuzhiyun
5453*4882a593Smuzhiyun return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
5454*4882a593Smuzhiyun }
5455*4882a593Smuzhiyun #endif
5456