blob: a792282f02f7f2b37fbc547746dc9f7e135d5830 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French1080ef72011-02-24 18:07:19 +00004 * Copyright (C) International Business Machines Corp., 2002,2011
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Igor Mammedov5c2503a2009-04-21 19:31:05 +040036#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/uaccess.h>
38#include <asm/processor.h>
Jeff Layton50b64e32009-06-02 06:55:20 -040039#include <linux/inet.h>
Paul Gortmaker143cb492011-07-01 14:23:34 -040040#include <linux/module.h>
Jeff Layton8a8798a2012-01-17 16:09:15 -050041#include <keys/user-type.h>
Steve French0e2beda2009-01-30 21:24:41 +000042#include <net/ipv6.h>
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040043#include <linux/parser.h>
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "cifspdu.h"
46#include "cifsglob.h"
47#include "cifsproto.h"
48#include "cifs_unicode.h"
49#include "cifs_debug.h"
50#include "cifs_fs_sb.h"
51#include "ntlmssp.h"
52#include "nterr.h"
53#include "rfc1002pdu.h"
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053054#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#define CIFS_PORT 445
57#define RFC1001_PORT 139
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059extern mempool_t *cifs_req_poolp;
60
Jeff Layton2de970f2010-10-06 19:51:12 -040061/* FIXME: should these be tunable? */
Jeff Layton9d002df2010-10-06 19:51:11 -040062#define TLINK_ERROR_EXPIRE (1 * HZ)
Jeff Layton2de970f2010-10-06 19:51:12 -040063#define TLINK_IDLE_EXPIRE (600 * HZ)
Jeff Layton9d002df2010-10-06 19:51:11 -040064
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040065enum {
66
67 /* Mount options that take no arguments */
68 Opt_user_xattr, Opt_nouser_xattr,
69 Opt_forceuid, Opt_noforceuid,
70 Opt_noblocksend, Opt_noautotune,
71 Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
72 Opt_mapchars, Opt_nomapchars, Opt_sfu,
73 Opt_nosfu, Opt_nodfs, Opt_posixpaths,
74 Opt_noposixpaths, Opt_nounix,
75 Opt_nocase,
76 Opt_brl, Opt_nobrl,
77 Opt_forcemandatorylock, Opt_setuids,
78 Opt_nosetuids, Opt_dynperm, Opt_nodynperm,
79 Opt_nohard, Opt_nosoft,
80 Opt_nointr, Opt_intr,
81 Opt_nostrictsync, Opt_strictsync,
82 Opt_serverino, Opt_noserverino,
83 Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
84 Opt_acl, Opt_noacl, Opt_locallease,
Jeff Layton1b359202012-09-19 15:20:27 -070085 Opt_sign, Opt_seal, Opt_noac,
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040086 Opt_fsc, Opt_mfsymlinks,
Jeff Laytond8162552012-03-23 14:40:56 -040087 Opt_multiuser, Opt_sloppy,
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040088
89 /* Mount options which take numeric value */
90 Opt_backupuid, Opt_backupgid, Opt_uid,
91 Opt_cruid, Opt_gid, Opt_file_mode,
92 Opt_dirmode, Opt_port,
93 Opt_rsize, Opt_wsize, Opt_actimeo,
94
95 /* Mount options which take string value */
96 Opt_user, Opt_pass, Opt_ip,
97 Opt_unc, Opt_domain,
98 Opt_srcaddr, Opt_prefixpath,
99 Opt_iocharset, Opt_sockopt,
100 Opt_netbiosname, Opt_servern,
Jeff Layton23db65f2012-05-15 12:20:51 -0400101 Opt_ver, Opt_vers, Opt_sec, Opt_cache,
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400102
103 /* Mount options to be ignored */
104 Opt_ignore,
105
106 /* Options which could be blank */
107 Opt_blank_pass,
Sachin Prabhu4fe9e962012-04-10 18:12:27 +0100108 Opt_blank_user,
109 Opt_blank_ip,
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400110
111 Opt_err
112};
113
114static const match_table_t cifs_mount_option_tokens = {
115
116 { Opt_user_xattr, "user_xattr" },
117 { Opt_nouser_xattr, "nouser_xattr" },
118 { Opt_forceuid, "forceuid" },
119 { Opt_noforceuid, "noforceuid" },
120 { Opt_noblocksend, "noblocksend" },
121 { Opt_noautotune, "noautotune" },
122 { Opt_hard, "hard" },
123 { Opt_soft, "soft" },
124 { Opt_perm, "perm" },
125 { Opt_noperm, "noperm" },
126 { Opt_mapchars, "mapchars" },
127 { Opt_nomapchars, "nomapchars" },
128 { Opt_sfu, "sfu" },
129 { Opt_nosfu, "nosfu" },
130 { Opt_nodfs, "nodfs" },
131 { Opt_posixpaths, "posixpaths" },
132 { Opt_noposixpaths, "noposixpaths" },
133 { Opt_nounix, "nounix" },
134 { Opt_nounix, "nolinux" },
135 { Opt_nocase, "nocase" },
136 { Opt_nocase, "ignorecase" },
137 { Opt_brl, "brl" },
138 { Opt_nobrl, "nobrl" },
139 { Opt_nobrl, "nolock" },
140 { Opt_forcemandatorylock, "forcemandatorylock" },
Pavel Shilovsky5cfdddc2012-03-27 20:51:15 +0400141 { Opt_forcemandatorylock, "forcemand" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400142 { Opt_setuids, "setuids" },
143 { Opt_nosetuids, "nosetuids" },
144 { Opt_dynperm, "dynperm" },
145 { Opt_nodynperm, "nodynperm" },
146 { Opt_nohard, "nohard" },
147 { Opt_nosoft, "nosoft" },
148 { Opt_nointr, "nointr" },
149 { Opt_intr, "intr" },
150 { Opt_nostrictsync, "nostrictsync" },
151 { Opt_strictsync, "strictsync" },
152 { Opt_serverino, "serverino" },
153 { Opt_noserverino, "noserverino" },
154 { Opt_rwpidforward, "rwpidforward" },
155 { Opt_cifsacl, "cifsacl" },
156 { Opt_nocifsacl, "nocifsacl" },
157 { Opt_acl, "acl" },
158 { Opt_noacl, "noacl" },
159 { Opt_locallease, "locallease" },
160 { Opt_sign, "sign" },
161 { Opt_seal, "seal" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400162 { Opt_noac, "noac" },
163 { Opt_fsc, "fsc" },
164 { Opt_mfsymlinks, "mfsymlinks" },
165 { Opt_multiuser, "multiuser" },
Jeff Laytond8162552012-03-23 14:40:56 -0400166 { Opt_sloppy, "sloppy" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400167
168 { Opt_backupuid, "backupuid=%s" },
169 { Opt_backupgid, "backupgid=%s" },
170 { Opt_uid, "uid=%s" },
171 { Opt_cruid, "cruid=%s" },
172 { Opt_gid, "gid=%s" },
173 { Opt_file_mode, "file_mode=%s" },
174 { Opt_dirmode, "dirmode=%s" },
175 { Opt_dirmode, "dir_mode=%s" },
176 { Opt_port, "port=%s" },
177 { Opt_rsize, "rsize=%s" },
178 { Opt_wsize, "wsize=%s" },
179 { Opt_actimeo, "actimeo=%s" },
180
Sachin Prabhu4fe9e962012-04-10 18:12:27 +0100181 { Opt_blank_user, "user=" },
182 { Opt_blank_user, "username=" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400183 { Opt_user, "user=%s" },
184 { Opt_user, "username=%s" },
185 { Opt_blank_pass, "pass=" },
186 { Opt_pass, "pass=%s" },
187 { Opt_pass, "password=%s" },
Sachin Prabhu4fe9e962012-04-10 18:12:27 +0100188 { Opt_blank_ip, "ip=" },
189 { Opt_blank_ip, "addr=" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400190 { Opt_ip, "ip=%s" },
191 { Opt_ip, "addr=%s" },
192 { Opt_unc, "unc=%s" },
193 { Opt_unc, "target=%s" },
194 { Opt_unc, "path=%s" },
195 { Opt_domain, "dom=%s" },
196 { Opt_domain, "domain=%s" },
197 { Opt_domain, "workgroup=%s" },
198 { Opt_srcaddr, "srcaddr=%s" },
199 { Opt_prefixpath, "prefixpath=%s" },
200 { Opt_iocharset, "iocharset=%s" },
201 { Opt_sockopt, "sockopt=%s" },
202 { Opt_netbiosname, "netbiosname=%s" },
203 { Opt_servern, "servern=%s" },
204 { Opt_ver, "ver=%s" },
Jeff Layton23db65f2012-05-15 12:20:51 -0400205 { Opt_vers, "vers=%s" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400206 { Opt_sec, "sec=%s" },
Jeff Layton15b6a472012-05-16 07:50:15 -0400207 { Opt_cache, "cache=%s" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400208
209 { Opt_ignore, "cred" },
210 { Opt_ignore, "credentials" },
Jeff Laytona557b972012-05-02 14:02:40 -0400211 { Opt_ignore, "cred=%s" },
212 { Opt_ignore, "credentials=%s" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400213 { Opt_ignore, "guest" },
214 { Opt_ignore, "rw" },
215 { Opt_ignore, "ro" },
216 { Opt_ignore, "suid" },
217 { Opt_ignore, "nosuid" },
218 { Opt_ignore, "exec" },
219 { Opt_ignore, "noexec" },
220 { Opt_ignore, "nodev" },
221 { Opt_ignore, "noauto" },
222 { Opt_ignore, "dev" },
223 { Opt_ignore, "mand" },
224 { Opt_ignore, "nomand" },
225 { Opt_ignore, "_netdev" },
226
227 { Opt_err, NULL }
228};
229
230enum {
231 Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
232 Opt_sec_ntlmsspi, Opt_sec_ntlmssp,
Jeff Layton76596242012-07-23 20:34:17 -0400233 Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2,
234 Opt_sec_ntlmv2i, Opt_sec_lanman,
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400235 Opt_sec_none,
236
237 Opt_sec_err
238};
239
240static const match_table_t cifs_secflavor_tokens = {
241 { Opt_sec_krb5, "krb5" },
242 { Opt_sec_krb5i, "krb5i" },
243 { Opt_sec_krb5p, "krb5p" },
244 { Opt_sec_ntlmsspi, "ntlmsspi" },
245 { Opt_sec_ntlmssp, "ntlmssp" },
246 { Opt_ntlm, "ntlm" },
247 { Opt_sec_ntlmi, "ntlmi" },
Jeff Layton76596242012-07-23 20:34:17 -0400248 { Opt_sec_ntlmv2, "nontlm" },
249 { Opt_sec_ntlmv2, "ntlmv2" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400250 { Opt_sec_ntlmv2i, "ntlmv2i" },
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400251 { Opt_sec_lanman, "lanman" },
252 { Opt_sec_none, "none" },
253
254 { Opt_sec_err, NULL }
255};
256
Jeff Layton15b6a472012-05-16 07:50:15 -0400257/* cache flavors */
258enum {
259 Opt_cache_loose,
260 Opt_cache_strict,
261 Opt_cache_none,
262 Opt_cache_err
263};
264
265static const match_table_t cifs_cacheflavor_tokens = {
266 { Opt_cache_loose, "loose" },
267 { Opt_cache_strict, "strict" },
268 { Opt_cache_none, "none" },
269 { Opt_cache_err, NULL }
270};
271
Jeff Layton23db65f2012-05-15 12:20:51 -0400272static const match_table_t cifs_smb_version_tokens = {
273 { Smb_1, SMB1_VERSION_STRING },
Steve French1080ef72011-02-24 18:07:19 +0000274 { Smb_21, SMB21_VERSION_STRING },
Jeff Layton23db65f2012-05-15 12:20:51 -0400275};
276
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300277static int ip_connect(struct TCP_Server_Info *server);
278static int generic_ip_connect(struct TCP_Server_Info *server);
Jeff Laytonb647c352010-10-28 11:16:44 -0400279static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
Jeff Layton2de970f2010-10-06 19:51:12 -0400280static void cifs_prune_tlinks(struct work_struct *work);
Jeff Laytonb9bce2e2011-07-06 08:10:39 -0400281static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
282 const char *devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Jeff Laytond5c56052008-12-01 18:42:33 -0500284/*
285 * cifs tcp session reconnection
286 *
287 * mark tcp session as reconnecting so temporarily locked
288 * mark all smb sessions as reconnecting for tcp session
289 * reconnect tcp session
290 * wake up waiters on reconnection? - (not needed currently)
291 */
Pavel Shilovsky28ea5292012-05-23 16:18:00 +0400292int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293cifs_reconnect(struct TCP_Server_Info *server)
294{
295 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500296 struct list_head *tmp, *tmp2;
Steve French96daf2b2011-05-27 04:34:02 +0000297 struct cifs_ses *ses;
298 struct cifs_tcon *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000299 struct mid_q_entry *mid_entry;
Jeff Layton3c1105d2011-05-22 07:09:13 -0400300 struct list_head retry_list;
Steve French50c2f752007-07-13 00:33:32 +0000301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000303 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000304 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 next time through the loop */
306 spin_unlock(&GlobalMid_Lock);
307 return rc;
308 } else
309 server->tcpStatus = CifsNeedReconnect;
310 spin_unlock(&GlobalMid_Lock);
311 server->maxBuf = 0;
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400312#ifdef CONFIG_CIFS_SMB2
313 server->max_read = 0;
314#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Joe Perchesb6b38f72010-04-21 03:50:45 +0000316 cFYI(1, "Reconnecting tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 /* before reconnecting the tcp session, mark the smb session (uid)
319 and the tid bad so they are not used until reconnected */
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500320 cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530321 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500322 list_for_each(tmp, &server->smb_ses_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000323 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
Jeff Layton14fbf502008-11-14 13:53:46 -0500324 ses->need_reconnect = true;
325 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500326 list_for_each(tmp2, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000327 tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500328 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530331 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /* do not want to be sending data on a socket we are freeing */
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500334 cFYI(1, "%s: tearing down socket", __func__);
Jeff Layton72ca5452008-12-01 07:09:36 -0500335 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000336 if (server->ssocket) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000337 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
338 server->ssocket->flags);
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800339 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000340 cFYI(1, "Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000341 server->ssocket->state,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000342 server->ssocket->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 sock_release(server->ssocket);
344 server->ssocket = NULL;
345 }
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -0500346 server->sequence_number = 0;
347 server->session_estab = false;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500348 kfree(server->session_key.response);
349 server->session_key.response = NULL;
350 server->session_key.len = 0;
Steve Frenchfda35942011-01-20 18:06:34 +0000351 server->lstrp = jiffies;
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500352 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500354 /* mark submitted MIDs for retry and issue callback */
Jeff Layton3c1105d2011-05-22 07:09:13 -0400355 INIT_LIST_HEAD(&retry_list);
356 cFYI(1, "%s: moving mids to private list", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 spin_lock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500358 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
359 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400360 if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
361 mid_entry->mid_state = MID_RETRY_NEEDED;
Jeff Layton3c1105d2011-05-22 07:09:13 -0400362 list_move(&mid_entry->qhead, &retry_list);
363 }
364 spin_unlock(&GlobalMid_Lock);
365
366 cFYI(1, "%s: issuing mid callbacks", __func__);
367 list_for_each_safe(tmp, tmp2, &retry_list) {
368 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500369 list_del_init(&mid_entry->qhead);
370 mid_entry->callback(mid_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400373 do {
Steve French6c3d8902006-07-31 22:46:20 +0000374 try_to_freeze();
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300375
376 /* we should try only the port we connected to before */
377 rc = generic_ip_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000378 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000379 cFYI(1, "reconnect error %d", rc);
Steve French0cb766a2005-04-28 22:41:11 -0700380 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 } else {
382 atomic_inc(&tcpSesReconnectCount);
383 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000384 if (server->tcpStatus != CifsExiting)
Steve Frenchfd88ce92011-04-12 01:01:14 +0000385 server->tcpStatus = CifsNeedNegotiate;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000386 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 }
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400388 } while (server->tcpStatus == CifsNeedReconnect);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return rc;
391}
392
Jeff Laytonc74093b2011-01-11 07:24:23 -0500393static void
394cifs_echo_request(struct work_struct *work)
395{
396 int rc;
397 struct TCP_Server_Info *server = container_of(work,
398 struct TCP_Server_Info, echo.work);
399
Jeff Layton247ec9b2011-02-04 17:09:50 -0500400 /*
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400401 * We cannot send an echo if it is disabled or until the
402 * NEGOTIATE_PROTOCOL request is done, which is indicated by
403 * server->ops->need_neg() == true. Also, no need to ping if
404 * we got a response recently.
Jeff Layton247ec9b2011-02-04 17:09:50 -0500405 */
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400406 if (!server->ops->need_neg || server->ops->need_neg(server) ||
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400407 (server->ops->can_echo && !server->ops->can_echo(server)) ||
Jeff Layton247ec9b2011-02-04 17:09:50 -0500408 time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
Jeff Laytonc74093b2011-01-11 07:24:23 -0500409 goto requeue_echo;
410
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400411 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
Jeff Laytonc74093b2011-01-11 07:24:23 -0500412 if (rc)
413 cFYI(1, "Unable to send echo request to server: %s",
414 server->hostname);
415
416requeue_echo:
Jeff Laytonda472fc2012-03-23 14:40:53 -0400417 queue_delayed_work(cifsiod_wq, &server->echo, SMB_ECHO_INTERVAL);
Jeff Laytonc74093b2011-01-11 07:24:23 -0500418}
419
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400420static bool
Jeff Layton2a37ef92011-10-19 15:29:23 -0400421allocate_buffers(struct TCP_Server_Info *server)
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400422{
Jeff Layton2a37ef92011-10-19 15:29:23 -0400423 if (!server->bigbuf) {
424 server->bigbuf = (char *)cifs_buf_get();
425 if (!server->bigbuf) {
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400426 cERROR(1, "No memory for large SMB response");
427 msleep(3000);
428 /* retry will check if exiting */
429 return false;
430 }
Jeff Layton2a37ef92011-10-19 15:29:23 -0400431 } else if (server->large_buf) {
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400432 /* we are reusing a dirty large buf, clear its start */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400433 memset(server->bigbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400434 }
435
Jeff Layton2a37ef92011-10-19 15:29:23 -0400436 if (!server->smallbuf) {
437 server->smallbuf = (char *)cifs_small_buf_get();
438 if (!server->smallbuf) {
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400439 cERROR(1, "No memory for SMB response");
440 msleep(1000);
441 /* retry will check if exiting */
442 return false;
443 }
444 /* beginning of smb buffer is cleared in our buf_get */
445 } else {
446 /* if existing small buf clear beginning */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400447 memset(server->smallbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400448 }
449
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400450 return true;
451}
452
Jeff Laytonba749e62011-10-11 06:41:32 -0400453static bool
454server_unresponsive(struct TCP_Server_Info *server)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400455{
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300456 /*
457 * We need to wait 2 echo intervals to make sure we handle such
458 * situations right:
459 * 1s client sends a normal SMB request
460 * 2s client gets a response
461 * 30s echo workqueue job pops, and decides we got a response recently
462 * and don't need to send another
463 * ...
464 * 65s kernel_recvmsg times out, and we see that we haven't gotten
465 * a response in >60s.
466 */
467 if (server->tcpStatus == CifsGood &&
468 time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) {
Jeff Laytonba749e62011-10-11 06:41:32 -0400469 cERROR(1, "Server %s has not responded in %d seconds. "
470 "Reconnecting...", server->hostname,
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300471 (2 * SMB_ECHO_INTERVAL) / HZ);
Jeff Laytonba749e62011-10-11 06:41:32 -0400472 cifs_reconnect(server);
473 wake_up(&server->response_q);
474 return true;
475 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400476
Jeff Laytonba749e62011-10-11 06:41:32 -0400477 return false;
478}
479
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400480/*
481 * kvec_array_init - clone a kvec array, and advance into it
482 * @new: pointer to memory for cloned array
483 * @iov: pointer to original array
484 * @nr_segs: number of members in original array
485 * @bytes: number of bytes to advance into the cloned array
486 *
487 * This function will copy the array provided in iov to a section of memory
488 * and advance the specified number of bytes into the new array. It returns
489 * the number of segments in the new array. "new" must be at least as big as
490 * the original iov array.
491 */
492static unsigned int
493kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs,
494 size_t bytes)
495{
496 size_t base = 0;
497
498 while (bytes || !iov->iov_len) {
499 int copy = min(bytes, iov->iov_len);
500
501 bytes -= copy;
502 base += copy;
503 if (iov->iov_len == base) {
504 iov++;
505 nr_segs--;
506 base = 0;
507 }
508 }
509 memcpy(new, iov, sizeof(*iov) * nr_segs);
510 new->iov_base += base;
511 new->iov_len -= base;
512 return nr_segs;
513}
514
Jeff Layton1041e3f2011-10-19 15:28:27 -0400515static struct kvec *
516get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs)
517{
518 struct kvec *new_iov;
519
520 if (server->iov && nr_segs <= server->nr_iov)
521 return server->iov;
522
523 /* not big enough -- allocate a new one and release the old */
524 new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS);
525 if (new_iov) {
526 kfree(server->iov);
527 server->iov = new_iov;
528 server->nr_iov = nr_segs;
529 }
530 return new_iov;
531}
532
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400533int
534cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
535 unsigned int nr_segs, unsigned int to_read)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400536{
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400537 int length = 0;
538 int total_read;
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400539 unsigned int segs;
Jeff Laytone831e6c2011-10-11 06:41:32 -0400540 struct msghdr smb_msg;
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400541 struct kvec *iov;
542
Jeff Layton1041e3f2011-10-19 15:28:27 -0400543 iov = get_server_iovec(server, nr_segs);
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400544 if (!iov)
545 return -ENOMEM;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400546
Jeff Laytone831e6c2011-10-11 06:41:32 -0400547 smb_msg.msg_control = NULL;
548 smb_msg.msg_controllen = 0;
549
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400550 for (total_read = 0; to_read; total_read += length, to_read -= length) {
Jeff Layton95edcff2011-12-01 20:22:41 -0500551 try_to_freeze();
552
Jeff Laytonba749e62011-10-11 06:41:32 -0400553 if (server_unresponsive(server)) {
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400554 total_read = -EAGAIN;
Jeff Laytonba749e62011-10-11 06:41:32 -0400555 break;
556 }
557
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400558 segs = kvec_array_init(iov, iov_orig, nr_segs, total_read);
559
560 length = kernel_recvmsg(server->ssocket, &smb_msg,
561 iov, segs, to_read, 0);
562
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400563 if (server->tcpStatus == CifsExiting) {
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400564 total_read = -ESHUTDOWN;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400565 break;
566 } else if (server->tcpStatus == CifsNeedReconnect) {
567 cifs_reconnect(server);
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400568 total_read = -EAGAIN;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400569 break;
570 } else if (length == -ERESTARTSYS ||
571 length == -EAGAIN ||
572 length == -EINTR) {
573 /*
574 * Minimum sleep to prevent looping, allowing socket
575 * to clear and app threads to set tcpStatus
576 * CifsNeedReconnect if server hung.
577 */
578 usleep_range(1000, 2000);
579 length = 0;
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400580 continue;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400581 } else if (length <= 0) {
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400582 cFYI(1, "Received no data or error: expecting %d "
583 "got %d", to_read, length);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400584 cifs_reconnect(server);
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400585 total_read = -EAGAIN;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400586 break;
587 }
588 }
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400589 return total_read;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400590}
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400591
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400592int
593cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
594 unsigned int to_read)
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400595{
596 struct kvec iov;
597
598 iov.iov_base = buf;
599 iov.iov_len = to_read;
600
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400601 return cifs_readv_from_socket(server, &iov, 1, to_read);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400602}
603
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400604static bool
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400605is_smb_response(struct TCP_Server_Info *server, unsigned char type)
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400606{
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400607 /*
608 * The first byte big endian of the length field,
609 * is actually not part of the length but the type
610 * with the most common, zero, as regular data.
611 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400612 switch (type) {
613 case RFC1002_SESSION_MESSAGE:
614 /* Regular SMB response */
615 return true;
616 case RFC1002_SESSION_KEEP_ALIVE:
617 cFYI(1, "RFC 1002 session keep alive");
618 break;
619 case RFC1002_POSITIVE_SESSION_RESPONSE:
620 cFYI(1, "RFC 1002 positive session response");
621 break;
622 case RFC1002_NEGATIVE_SESSION_RESPONSE:
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400623 /*
624 * We get this from Windows 98 instead of an error on
625 * SMB negprot response.
626 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400627 cFYI(1, "RFC 1002 negative session response");
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400628 /* give server a second to clean up */
629 msleep(1000);
630 /*
631 * Always try 445 first on reconnect since we get NACK
632 * on some if we ever connected to port 139 (the NACK
633 * is since we do not begin with RFC1001 session
634 * initialize frame).
635 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400636 cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400637 cifs_reconnect(server);
638 wake_up(&server->response_q);
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400639 break;
640 default:
641 cERROR(1, "RFC 1002 unknown response type 0x%x", type);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400642 cifs_reconnect(server);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400643 }
644
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400645 return false;
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400646}
647
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400648void
649dequeue_mid(struct mid_q_entry *mid, bool malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400650{
651#ifdef CONFIG_CIFS_STATS2
652 mid->when_received = jiffies;
653#endif
654 spin_lock(&GlobalMid_Lock);
655 if (!malformed)
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400656 mid->mid_state = MID_RESPONSE_RECEIVED;
Jeff Laytonea1f4502011-10-19 15:29:05 -0400657 else
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400658 mid->mid_state = MID_RESPONSE_MALFORMED;
Jeff Laytonea1f4502011-10-19 15:29:05 -0400659 list_del_init(&mid->qhead);
660 spin_unlock(&GlobalMid_Lock);
661}
662
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400663static void
664handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400665 char *buf, int malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400666{
Pavel Shilovsky316cf942012-05-23 14:31:03 +0400667 if (server->ops->check_trans2 &&
668 server->ops->check_trans2(mid, server, buf, malformed))
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400669 return;
Jeff Laytonea1f4502011-10-19 15:29:05 -0400670 mid->resp_buf = buf;
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400671 mid->large_buf = server->large_buf;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400672 /* Was previous buf put in mpx struct for multi-rsp? */
673 if (!mid->multiRsp) {
674 /* smb buffer will be freed by user thread */
675 if (server->large_buf)
676 server->bigbuf = NULL;
677 else
678 server->smallbuf = NULL;
679 }
Jeff Laytonffc00e22011-10-19 15:29:13 -0400680 dequeue_mid(mid, malformed);
Pavel Shilovskyad69bae2011-08-01 13:19:43 +0400681}
682
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400683static void clean_demultiplex_info(struct TCP_Server_Info *server)
684{
685 int length;
686
687 /* take it off the list, if it's not already */
688 spin_lock(&cifs_tcp_ses_lock);
689 list_del_init(&server->tcp_ses_list);
690 spin_unlock(&cifs_tcp_ses_lock);
691
692 spin_lock(&GlobalMid_Lock);
693 server->tcpStatus = CifsExiting;
694 spin_unlock(&GlobalMid_Lock);
695 wake_up_all(&server->response_q);
696
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400697 /* check if we have blocked requests that need to free */
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300698 spin_lock(&server->req_lock);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400699 if (server->credits <= 0)
700 server->credits = 1;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300701 spin_unlock(&server->req_lock);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400702 /*
703 * Although there should not be any requests blocked on this queue it
704 * can not hurt to be paranoid and try to wake up requests that may
705 * haven been blocked when more than 50 at time were on the wire to the
706 * same server - they now will see the session is in exit state and get
707 * out of SendReceive.
708 */
709 wake_up_all(&server->request_q);
710 /* give those requests time to exit */
711 msleep(125);
712
713 if (server->ssocket) {
714 sock_release(server->ssocket);
715 server->ssocket = NULL;
716 }
717
718 if (!list_empty(&server->pending_mid_q)) {
719 struct list_head dispose_list;
720 struct mid_q_entry *mid_entry;
721 struct list_head *tmp, *tmp2;
722
723 INIT_LIST_HEAD(&dispose_list);
724 spin_lock(&GlobalMid_Lock);
725 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
726 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400727 cFYI(1, "Clearing mid 0x%llx", mid_entry->mid);
728 mid_entry->mid_state = MID_SHUTDOWN;
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400729 list_move(&mid_entry->qhead, &dispose_list);
730 }
731 spin_unlock(&GlobalMid_Lock);
732
733 /* now walk dispose list and issue callbacks */
734 list_for_each_safe(tmp, tmp2, &dispose_list) {
735 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400736 cFYI(1, "Callback mid 0x%llx", mid_entry->mid);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400737 list_del_init(&mid_entry->qhead);
738 mid_entry->callback(mid_entry);
739 }
740 /* 1/8th of sec is more than enough time for them to exit */
741 msleep(125);
742 }
743
744 if (!list_empty(&server->pending_mid_q)) {
745 /*
746 * mpx threads have not exited yet give them at least the smb
747 * send timeout time for long ops.
748 *
749 * Due to delays on oplock break requests, we need to wait at
750 * least 45 seconds before giving up on a request getting a
751 * response and going ahead and killing cifsd.
752 */
753 cFYI(1, "Wait for exit from demultiplex thread");
754 msleep(46000);
755 /*
756 * If threads still have not exited they are probably never
757 * coming home not much else we can do but free the memory.
758 */
759 }
760
761 kfree(server->hostname);
Jeff Layton1041e3f2011-10-19 15:28:27 -0400762 kfree(server->iov);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400763 kfree(server);
764
765 length = atomic_dec_return(&tcpSesAllocCount);
766 if (length > 0)
767 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
768 GFP_KERNEL);
769}
770
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400771static int
Jeff Laytone9097ab2011-10-19 15:29:40 -0400772standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
773{
774 int length;
775 char *buf = server->smallbuf;
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400776 unsigned int pdu_length = get_rfc1002_length(buf);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400777
778 /* make sure this will fit in a large buffer */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400779 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - 4) {
Jeff Laytone9097ab2011-10-19 15:29:40 -0400780 cERROR(1, "SMB response too long (%u bytes)",
781 pdu_length);
782 cifs_reconnect(server);
783 wake_up(&server->response_q);
784 return -EAGAIN;
785 }
786
787 /* switch to large buffer if too big for a small one */
788 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
789 server->large_buf = true;
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400790 memcpy(server->bigbuf, buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400791 buf = server->bigbuf;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400792 }
793
794 /* now read the rest */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400795 length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
796 pdu_length - HEADER_SIZE(server) + 1 + 4);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400797 if (length < 0)
798 return length;
799 server->total_read += length;
800
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400801 dump_smb(buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400802
803 /*
804 * We know that we received enough to get to the MID as we
805 * checked the pdu_length earlier. Now check to see
806 * if the rest of the header is OK. We borrow the length
807 * var for the rest of the loop to avoid a new stack var.
808 *
809 * 48 bytes is enough to display the header and a little bit
810 * into the payload for debugging purposes.
811 */
Pavel Shilovsky8aa26f32012-05-17 13:25:35 +0400812 length = server->ops->check_message(buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400813 if (length != 0)
814 cifs_dump_mem("Bad SMB: ", buf,
815 min_t(unsigned int, server->total_read, 48));
816
Pavel Shilovsky2e44b282012-09-18 16:20:33 -0700817 if (server->ops->is_status_pending &&
818 server->ops->is_status_pending(buf, server, length))
819 return -1;
820
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500821 if (!mid)
822 return length;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400823
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400824 handle_mid(mid, server, buf, length);
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500825 return 0;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400826}
827
828static int
Al Viro7c97c202011-06-21 08:51:28 -0400829cifs_demultiplex_thread(void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
831 int length;
Al Viro7c97c202011-06-21 08:51:28 -0400832 struct TCP_Server_Info *server = p;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400833 unsigned int pdu_length;
834 char *buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 struct task_struct *task_to_wake = NULL;
836 struct mid_q_entry *mid_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 current->flags |= PF_MEMALLOC;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000839 cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400840
841 length = atomic_inc_return(&tcpSesAllocCount);
842 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000843 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
844 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700846 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000847 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700848 if (try_to_freeze())
849 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700850
Jeff Layton2a37ef92011-10-19 15:29:23 -0400851 if (!allocate_buffers(server))
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400852 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700853
Jeff Layton2a37ef92011-10-19 15:29:23 -0400854 server->large_buf = false;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400855 buf = server->smallbuf;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000856 pdu_length = 4; /* enough to get RFC1001 header */
Steve Frenchfda35942011-01-20 18:06:34 +0000857
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400858 length = cifs_read_from_socket(server, buf, pdu_length);
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400859 if (length < 0)
Steve Frenchfda35942011-01-20 18:06:34 +0000860 continue;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400861 server->total_read = length;
Steve French67010fb2005-04-28 22:41:09 -0700862
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400863 /*
864 * The right amount was read from socket - 4 bytes,
865 * so we can now interpret the length field.
866 */
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400867 pdu_length = get_rfc1002_length(buf);
Steve French46810cb2005-04-28 22:41:09 -0700868
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400869 cFYI(1, "RFC1002 header 0x%x", pdu_length);
870 if (!is_smb_response(server, buf[0]))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000871 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700872
Jeff Layton89482a52011-10-19 15:28:57 -0400873 /* make sure we have enough to get to the MID */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400874 if (pdu_length < HEADER_SIZE(server) - 1 - 4) {
Jeff Layton89482a52011-10-19 15:28:57 -0400875 cERROR(1, "SMB response too short (%u bytes)",
876 pdu_length);
877 cifs_reconnect(server);
878 wake_up(&server->response_q);
879 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700880 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400881
Jeff Layton89482a52011-10-19 15:28:57 -0400882 /* read down to the MID */
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400883 length = cifs_read_from_socket(server, buf + 4,
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400884 HEADER_SIZE(server) - 1 - 4);
Jeff Layton89482a52011-10-19 15:28:57 -0400885 if (length < 0)
886 continue;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400887 server->total_read += length;
Jeff Layton89482a52011-10-19 15:28:57 -0400888
Pavel Shilovsky8aa26f32012-05-17 13:25:35 +0400889 mid_entry = server->ops->find_mid(server, buf);
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400890
Jeff Layton44d22d82011-10-19 15:29:49 -0400891 if (!mid_entry || !mid_entry->receive)
892 length = standard_receive3(server, mid_entry);
893 else
894 length = mid_entry->receive(server, mid_entry);
895
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400896 if (length < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700897 continue;
898
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400899 if (server->large_buf)
Jeff Laytone9097ab2011-10-19 15:29:40 -0400900 buf = server->bigbuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700901
Steve Frenchfda35942011-01-20 18:06:34 +0000902 server->lstrp = jiffies;
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500903 if (mid_entry != NULL) {
Jeff Layton2a37ef92011-10-19 15:29:23 -0400904 if (!mid_entry->multiRsp || mid_entry->multiEnd)
905 mid_entry->callback(mid_entry);
Pavel Shilovsky7f0adb52012-05-28 15:50:10 +0400906 } else if (!server->ops->is_oplock_break ||
907 !server->ops->is_oplock_break(buf, server)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000908 cERROR(1, "No task to wake, unknown frame received! "
Jeff Layton80975312011-01-11 07:24:02 -0500909 "NumMids %d", atomic_read(&midCount));
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400910 cifs_dump_mem("Received Data is: ", buf,
911 HEADER_SIZE(server));
Steve French39798772006-05-31 22:40:51 +0000912#ifdef CONFIG_CIFS_DEBUG2
Pavel Shilovsky7f0adb52012-05-28 15:50:10 +0400913 if (server->ops->dump_detail)
914 server->ops->dump_detail(buf);
Steve French39798772006-05-31 22:40:51 +0000915 cifs_dump_mids(server);
916#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000917
Steve Frenche4eb2952005-04-28 22:41:09 -0700918 }
919 } /* end while !EXITING */
920
Justin P. Mattockfd62cb72011-02-24 22:15:02 -0800921 /* buffer usually freed in free_mid - need to free it here on exit */
Jeff Layton2a37ef92011-10-19 15:29:23 -0400922 cifs_buf_release(server->bigbuf);
923 if (server->smallbuf) /* no sense logging a debug message if NULL */
924 cifs_small_buf_release(server->smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400926 task_to_wake = xchg(&server->tsk, NULL);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400927 clean_demultiplex_info(server);
Steve French50c2f752007-07-13 00:33:32 +0000928
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400929 /* if server->tsk was NULL then wait for a signal before exiting */
930 if (!task_to_wake) {
931 set_current_state(TASK_INTERRUPTIBLE);
932 while (!signal_pending(current)) {
933 schedule();
934 set_current_state(TASK_INTERRUPTIBLE);
935 }
936 set_current_state(TASK_RUNNING);
937 }
938
Jeff Layton0468a2c2008-12-01 07:09:35 -0500939 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940}
941
Jeff Laytonc359cf32007-11-16 22:22:06 +0000942/* extract the host portion of the UNC string */
943static char *
944extract_hostname(const char *unc)
945{
946 const char *src;
947 char *dst, *delim;
948 unsigned int len;
949
950 /* skip double chars at beginning of string */
951 /* BB: check validity of these bytes? */
952 src = unc + 2;
953
954 /* delimiter between hostname and sharename is always '\\' now */
955 delim = strchr(src, '\\');
956 if (!delim)
957 return ERR_PTR(-EINVAL);
958
959 len = delim - src;
960 dst = kmalloc((len + 1), GFP_KERNEL);
961 if (dst == NULL)
962 return ERR_PTR(-ENOMEM);
963
964 memcpy(dst, src, len);
965 dst[len] = '\0';
966
967 return dst;
968}
969
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400970static int get_option_ul(substring_t args[], unsigned long *option)
971{
972 int rc;
973 char *string;
974
975 string = match_strdup(args);
976 if (string == NULL)
977 return -ENOMEM;
Sachin Prabhubfa890a2012-04-13 14:04:32 +0100978 rc = kstrtoul(string, 0, option);
Sachin Prabhu8830d7e2012-03-23 14:40:56 -0400979 kfree(string);
980
981 return rc;
982}
983
984
985static int cifs_parse_security_flavors(char *value,
986 struct smb_vol *vol)
987{
988
989 substring_t args[MAX_OPT_ARGS];
990
991 switch (match_token(value, cifs_secflavor_tokens, args)) {
992 case Opt_sec_krb5:
993 vol->secFlg |= CIFSSEC_MAY_KRB5;
994 break;
995 case Opt_sec_krb5i:
996 vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN;
997 break;
998 case Opt_sec_krb5p:
999 /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */
1000 cERROR(1, "Krb5 cifs privacy not supported");
1001 break;
1002 case Opt_sec_ntlmssp:
1003 vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
1004 break;
1005 case Opt_sec_ntlmsspi:
1006 vol->secFlg |= CIFSSEC_MAY_NTLMSSP | CIFSSEC_MUST_SIGN;
1007 break;
1008 case Opt_ntlm:
1009 /* ntlm is default so can be turned off too */
1010 vol->secFlg |= CIFSSEC_MAY_NTLM;
1011 break;
1012 case Opt_sec_ntlmi:
1013 vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN;
1014 break;
Jeff Layton76596242012-07-23 20:34:17 -04001015 case Opt_sec_ntlmv2:
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001016 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
1017 break;
1018 case Opt_sec_ntlmv2i:
1019 vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN;
1020 break;
1021#ifdef CONFIG_CIFS_WEAK_PW_HASH
1022 case Opt_sec_lanman:
1023 vol->secFlg |= CIFSSEC_MAY_LANMAN;
1024 break;
1025#endif
1026 case Opt_sec_none:
1027 vol->nullauth = 1;
1028 break;
1029 default:
1030 cERROR(1, "bad security option: %s", value);
1031 return 1;
1032 }
1033
1034 return 0;
1035}
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037static int
Jeff Layton15b6a472012-05-16 07:50:15 -04001038cifs_parse_cache_flavor(char *value, struct smb_vol *vol)
1039{
1040 substring_t args[MAX_OPT_ARGS];
1041
1042 switch (match_token(value, cifs_cacheflavor_tokens, args)) {
1043 case Opt_cache_loose:
1044 vol->direct_io = false;
1045 vol->strict_io = false;
1046 break;
1047 case Opt_cache_strict:
1048 vol->direct_io = false;
1049 vol->strict_io = true;
1050 break;
1051 case Opt_cache_none:
1052 vol->direct_io = true;
1053 vol->strict_io = false;
1054 break;
1055 default:
1056 cERROR(1, "bad cache= option: %s", value);
1057 return 1;
1058 }
1059 return 0;
1060}
1061
1062static int
Jeff Layton23db65f2012-05-15 12:20:51 -04001063cifs_parse_smb_version(char *value, struct smb_vol *vol)
1064{
1065 substring_t args[MAX_OPT_ARGS];
1066
1067 switch (match_token(value, cifs_smb_version_tokens, args)) {
1068 case Smb_1:
1069 vol->ops = &smb1_operations;
1070 vol->vals = &smb1_values;
1071 break;
Steve French1080ef72011-02-24 18:07:19 +00001072#ifdef CONFIG_CIFS_SMB2
1073 case Smb_21:
1074 vol->ops = &smb21_operations;
1075 vol->vals = &smb21_values;
1076 break;
1077#endif
Jeff Layton23db65f2012-05-15 12:20:51 -04001078 default:
1079 cERROR(1, "Unknown vers= option specified: %s", value);
1080 return 1;
1081 }
1082 return 0;
1083}
1084
1085static int
Sean Finneyb9468452011-04-11 13:19:32 +00001086cifs_parse_mount_options(const char *mountdata, const char *devname,
Steve French50c2f752007-07-13 00:33:32 +00001087 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001089 char *data, *end;
Vasily Averin957df452011-06-06 11:33:12 +04001090 char *mountdata_copy = NULL, *options;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 unsigned int temp_len, i, j;
1092 char separator[2];
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001093 short int override_uid = -1;
1094 short int override_gid = -1;
1095 bool uid_specified = false;
1096 bool gid_specified = false;
Jeff Laytond8162552012-03-23 14:40:56 -04001097 bool sloppy = false;
1098 char *invalid = NULL;
Jeff Layton88463992010-11-22 15:31:03 -05001099 char *nodename = utsname()->nodename;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001100 char *string = NULL;
1101 char *tmp_end, *value;
1102 char delim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +00001105 separator[1] = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001106 delim = separator[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Jeff Layton88463992010-11-22 15:31:03 -05001108 /*
1109 * does not have to be perfect mapping since field is
1110 * informational, only used for servers that do not support
1111 * port 445 and it can be overridden at mount time
1112 */
Jeff Layton1397f2e2011-01-07 11:30:28 -05001113 memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
1114 for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
Jeff Layton88463992010-11-22 15:31:03 -05001115 vol->source_rfc1001_name[i] = toupper(nodename[i]);
1116
Jeff Layton1397f2e2011-01-07 11:30:28 -05001117 vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001118 /* null target name indicates to use *SMBSERVR default called name
1119 if we end up sending RFC1001 session initialize */
1120 vol->target_rfc1001_name[0] = 0;
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001121 vol->cred_uid = current_uid();
1122 vol->linux_uid = current_uid();
David Howellsa001e5b2008-11-14 10:38:47 +11001123 vol->linux_gid = current_gid();
Jeff Laytonf55ed1a2009-05-26 16:28:11 -04001124
1125 /* default to only allowing write access to owner of the mount */
1126 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Jeremy Allisonac670552005-06-22 17:26:35 -07001129 /* default is always to request posix paths. */
1130 vol->posix_paths = 1;
Jeff Laytona0c92172009-05-27 15:40:47 -04001131 /* default to using server inode numbers where available */
1132 vol->server_ino = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001133
Jeff Layton1b359202012-09-19 15:20:27 -07001134 /* default is to use strict cifs caching semantics */
1135 vol->strict_io = true;
1136
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301137 vol->actimeo = CIFS_DEF_ACTIMEO;
1138
Jeff Layton23db65f2012-05-15 12:20:51 -04001139 /* FIXME: add autonegotiation -- for now, SMB1 is default */
1140 vol->ops = &smb1_operations;
1141 vol->vals = &smb1_values;
1142
Sean Finneyb9468452011-04-11 13:19:32 +00001143 if (!mountdata)
1144 goto cifs_parse_mount_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Sean Finneyb9468452011-04-11 13:19:32 +00001146 mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL);
1147 if (!mountdata_copy)
1148 goto cifs_parse_mount_err;
1149
1150 options = mountdata_copy;
Pavel Shilovsky4906e502011-04-14 22:00:56 +04001151 end = options + strlen(options);
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001152
Steve French50c2f752007-07-13 00:33:32 +00001153 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001154 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 separator[0] = options[4];
1156 options += 5;
1157 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001158 cFYI(1, "Null separator not allowed");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 }
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001161 vol->backupuid_specified = false; /* no backup intent for a user */
1162 vol->backupgid_specified = false; /* no backup intent for a group */
Steve French50c2f752007-07-13 00:33:32 +00001163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 while ((data = strsep(&options, separator)) != NULL) {
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001165 substring_t args[MAX_OPT_ARGS];
1166 unsigned long option;
1167 int token;
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if (!*data)
1170 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001172 token = match_token(data, cifs_mount_option_tokens, args);
1173
1174 switch (token) {
1175
1176 /* Ingnore the following */
1177 case Opt_ignore:
1178 break;
1179
1180 /* Boolean values */
1181 case Opt_user_xattr:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 vol->no_xattr = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001183 break;
1184 case Opt_nouser_xattr:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 vol->no_xattr = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001186 break;
1187 case Opt_forceuid:
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001188 override_uid = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001189 break;
1190 case Opt_noforceuid:
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001191 override_uid = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001192 break;
1193 case Opt_noblocksend:
Steve Frenchedf1ae42008-10-29 00:47:57 +00001194 vol->noblocksnd = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001195 break;
1196 case Opt_noautotune:
Steve Frenchedf1ae42008-10-29 00:47:57 +00001197 vol->noautotune = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001198 break;
1199 case Opt_hard:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 vol->retry = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001201 break;
1202 case Opt_soft:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 vol->retry = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001204 break;
1205 case Opt_perm:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 vol->noperm = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001207 break;
1208 case Opt_noperm:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 vol->noperm = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001210 break;
1211 case Opt_mapchars:
Steve French6a0b4822005-04-28 22:41:05 -07001212 vol->remap = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001213 break;
1214 case Opt_nomapchars:
Steve French6a0b4822005-04-28 22:41:05 -07001215 vol->remap = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001216 break;
1217 case Opt_sfu:
Steve French50c2f752007-07-13 00:33:32 +00001218 vol->sfu_emul = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001219 break;
1220 case Opt_nosfu:
Steve French50c2f752007-07-13 00:33:32 +00001221 vol->sfu_emul = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001222 break;
1223 case Opt_nodfs:
Steve French2c1b8612008-10-16 18:35:21 +00001224 vol->nodfs = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001225 break;
1226 case Opt_posixpaths:
Jeremy Allisonac670552005-06-22 17:26:35 -07001227 vol->posix_paths = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001228 break;
1229 case Opt_noposixpaths:
Jeremy Allisonac670552005-06-22 17:26:35 -07001230 vol->posix_paths = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001231 break;
1232 case Opt_nounix:
Steve Frenchc18c8422007-07-18 23:21:09 +00001233 vol->no_linux_ext = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001234 break;
1235 case Opt_nocase:
Steve French50c2f752007-07-13 00:33:32 +00001236 vol->nocase = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001237 break;
1238 case Opt_brl:
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001239 vol->nobrl = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001240 break;
1241 case Opt_nobrl:
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001242 vol->nobrl = 1;
Pavel Shilovsky5cfdddc2012-03-27 20:51:15 +04001243 /*
1244 * turn off mandatory locking in mode
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001245 * if remote locking is turned off since the
Pavel Shilovsky5cfdddc2012-03-27 20:51:15 +04001246 * local vfs will do advisory
1247 */
Steve French50c2f752007-07-13 00:33:32 +00001248 if (vol->file_mode ==
1249 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001250 vol->file_mode = S_IALLUGO;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001251 break;
1252 case Opt_forcemandatorylock:
Steve French13a6e422008-12-02 17:24:33 +00001253 vol->mand_lock = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001254 break;
1255 case Opt_setuids:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 vol->setuids = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001257 break;
1258 case Opt_nosetuids:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 vol->setuids = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001260 break;
1261 case Opt_dynperm:
Jeff Laytond0a9c072008-05-12 22:23:49 +00001262 vol->dynperm = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001263 break;
1264 case Opt_nodynperm:
Jeff Laytond0a9c072008-05-12 22:23:49 +00001265 vol->dynperm = false;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001266 break;
1267 case Opt_nohard:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 vol->retry = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001269 break;
1270 case Opt_nosoft:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 vol->retry = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001272 break;
1273 case Opt_nointr:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 vol->intr = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001275 break;
1276 case Opt_intr:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 vol->intr = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001278 break;
1279 case Opt_nostrictsync:
Steve Frenchbe652442009-02-23 15:21:59 +00001280 vol->nostrictsync = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001281 break;
1282 case Opt_strictsync:
Steve Frenchbe652442009-02-23 15:21:59 +00001283 vol->nostrictsync = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001284 break;
1285 case Opt_serverino:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 vol->server_ino = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001287 break;
1288 case Opt_noserverino:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 vol->server_ino = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001290 break;
1291 case Opt_rwpidforward:
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001292 vol->rwpidforward = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001293 break;
1294 case Opt_cifsacl:
Steve French0a4b92c2006-01-12 15:44:21 -08001295 vol->cifs_acl = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001296 break;
1297 case Opt_nocifsacl:
Steve French0a4b92c2006-01-12 15:44:21 -08001298 vol->cifs_acl = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001299 break;
1300 case Opt_acl:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 vol->no_psx_acl = 0;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001302 break;
1303 case Opt_noacl:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 vol->no_psx_acl = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001305 break;
1306 case Opt_locallease:
Steve French84210e92008-10-23 04:42:37 +00001307 vol->local_lease = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001308 break;
1309 case Opt_sign:
Steve French750d1152006-06-27 06:28:30 +00001310 vol->secFlg |= CIFSSEC_MUST_SIGN;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001311 break;
1312 case Opt_seal:
Steve French95b1cb92008-05-15 16:44:38 +00001313 /* we do not do the following in secFlags because seal
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001314 * is a per tree connection (mount) not a per socket
1315 * or per-smb connection option in the protocol
1316 * vol->secFlg |= CIFSSEC_MUST_SEAL;
1317 */
Steve French95b1cb92008-05-15 16:44:38 +00001318 vol->seal = 1;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001319 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001320 case Opt_noac:
Steve French50c2f752007-07-13 00:33:32 +00001321 printk(KERN_WARNING "CIFS: Mount option noac not "
1322 "supported. Instead set "
1323 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001324 break;
1325 case Opt_fsc:
Suresh Jayaraman607a5692010-11-24 17:49:05 +05301326#ifndef CONFIG_CIFS_FSCACHE
Jeff Layton83fb0862011-06-08 07:35:24 -04001327 cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE "
Suresh Jayaraman607a5692010-11-24 17:49:05 +05301328 "kernel config option set");
Sean Finneyb9468452011-04-11 13:19:32 +00001329 goto cifs_parse_mount_err;
Suresh Jayaraman607a5692010-11-24 17:49:05 +05301330#endif
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05301331 vol->fsc = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001332 break;
1333 case Opt_mfsymlinks:
Stefan Metzmacher736a3322010-07-30 14:56:00 +02001334 vol->mfsymlinks = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001335 break;
1336 case Opt_multiuser:
Jeff Layton0eb8a132010-10-06 19:51:12 -04001337 vol->multiuser = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001338 break;
Jeff Laytond8162552012-03-23 14:40:56 -04001339 case Opt_sloppy:
1340 sloppy = true;
1341 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001342
1343 /* Numeric Values */
1344 case Opt_backupuid:
1345 if (get_option_ul(args, &option)) {
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001346 cERROR(1, "%s: Invalid backupuid value",
1347 __func__);
1348 goto cifs_parse_mount_err;
1349 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001350 vol->backupuid = option;
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001351 vol->backupuid_specified = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001352 break;
1353 case Opt_backupgid:
1354 if (get_option_ul(args, &option)) {
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001355 cERROR(1, "%s: Invalid backupgid value",
1356 __func__);
1357 goto cifs_parse_mount_err;
1358 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001359 vol->backupgid = option;
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001360 vol->backupgid_specified = true;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001361 break;
1362 case Opt_uid:
1363 if (get_option_ul(args, &option)) {
1364 cERROR(1, "%s: Invalid uid value",
1365 __func__);
Sean Finneyb9468452011-04-11 13:19:32 +00001366 goto cifs_parse_mount_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001368 vol->linux_uid = option;
1369 uid_specified = true;
1370 break;
1371 case Opt_cruid:
1372 if (get_option_ul(args, &option)) {
1373 cERROR(1, "%s: Invalid cruid value",
1374 __func__);
1375 goto cifs_parse_mount_err;
1376 }
1377 vol->cred_uid = option;
1378 break;
1379 case Opt_gid:
1380 if (get_option_ul(args, &option)) {
1381 cERROR(1, "%s: Invalid gid value",
1382 __func__);
1383 goto cifs_parse_mount_err;
1384 }
1385 vol->linux_gid = option;
1386 gid_specified = true;
1387 break;
1388 case Opt_file_mode:
1389 if (get_option_ul(args, &option)) {
1390 cERROR(1, "%s: Invalid file_mode value",
1391 __func__);
1392 goto cifs_parse_mount_err;
1393 }
1394 vol->file_mode = option;
1395 break;
1396 case Opt_dirmode:
1397 if (get_option_ul(args, &option)) {
1398 cERROR(1, "%s: Invalid dir_mode value",
1399 __func__);
1400 goto cifs_parse_mount_err;
1401 }
1402 vol->dir_mode = option;
1403 break;
1404 case Opt_port:
1405 if (get_option_ul(args, &option)) {
1406 cERROR(1, "%s: Invalid port value",
1407 __func__);
1408 goto cifs_parse_mount_err;
1409 }
1410 vol->port = option;
1411 break;
1412 case Opt_rsize:
1413 if (get_option_ul(args, &option)) {
1414 cERROR(1, "%s: Invalid rsize value",
1415 __func__);
1416 goto cifs_parse_mount_err;
1417 }
1418 vol->rsize = option;
1419 break;
1420 case Opt_wsize:
1421 if (get_option_ul(args, &option)) {
1422 cERROR(1, "%s: Invalid wsize value",
1423 __func__);
1424 goto cifs_parse_mount_err;
1425 }
1426 vol->wsize = option;
1427 break;
1428 case Opt_actimeo:
1429 if (get_option_ul(args, &option)) {
1430 cERROR(1, "%s: Invalid actimeo value",
1431 __func__);
1432 goto cifs_parse_mount_err;
1433 }
1434 vol->actimeo = HZ * option;
1435 if (vol->actimeo > CIFS_MAX_ACTIMEO) {
1436 cERROR(1, "CIFS: attribute cache"
1437 "timeout too large");
1438 goto cifs_parse_mount_err;
1439 }
1440 break;
1441
1442 /* String Arguments */
1443
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001444 case Opt_blank_user:
1445 /* null user, ie. anonymous authentication */
1446 vol->nullauth = 1;
1447 vol->username = NULL;
1448 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001449 case Opt_user:
1450 string = match_strdup(args);
1451 if (string == NULL)
1452 goto out_nomem;
1453
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001454 if (strnlen(string, MAX_USERNAME_SIZE) >
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001455 MAX_USERNAME_SIZE) {
1456 printk(KERN_WARNING "CIFS: username too long\n");
1457 goto cifs_parse_mount_err;
1458 }
1459 vol->username = kstrdup(string, GFP_KERNEL);
1460 if (!vol->username) {
1461 printk(KERN_WARNING "CIFS: no memory "
1462 "for username\n");
1463 goto cifs_parse_mount_err;
1464 }
1465 break;
1466 case Opt_blank_pass:
1467 vol->password = NULL;
1468 break;
1469 case Opt_pass:
1470 /* passwords have to be handled differently
1471 * to allow the character used for deliminator
1472 * to be passed within them
1473 */
1474
1475 /* Obtain the value string */
1476 value = strchr(data, '=');
Sachin Prabhu10238072012-03-28 18:07:08 +01001477 value++;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001478
1479 /* Set tmp_end to end of the string */
1480 tmp_end = (char *) value + strlen(value);
1481
1482 /* Check if following character is the deliminator
1483 * If yes, we have encountered a double deliminator
1484 * reset the NULL character to the deliminator
1485 */
Suresh Jayaramane73f8432012-06-12 07:15:50 +05301486 if (tmp_end < end && tmp_end[1] == delim) {
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001487 tmp_end[0] = delim;
1488
Suresh Jayaramane73f8432012-06-12 07:15:50 +05301489 /* Keep iterating until we get to a single
1490 * deliminator OR the end
1491 */
1492 while ((tmp_end = strchr(tmp_end, delim))
1493 != NULL && (tmp_end[1] == delim)) {
1494 tmp_end = (char *) &tmp_end[2];
1495 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001496
Suresh Jayaramane73f8432012-06-12 07:15:50 +05301497 /* Reset var options to point to next element */
1498 if (tmp_end) {
1499 tmp_end[0] = '\0';
1500 options = (char *) &tmp_end[1];
1501 } else
1502 /* Reached the end of the mount option
1503 * string */
1504 options = end;
1505 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001506
1507 /* Now build new password string */
1508 temp_len = strlen(value);
1509 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
1510 if (vol->password == NULL) {
1511 printk(KERN_WARNING "CIFS: no memory "
1512 "for password\n");
1513 goto cifs_parse_mount_err;
1514 }
1515
1516 for (i = 0, j = 0; i < temp_len; i++, j++) {
1517 vol->password[j] = value[i];
1518 if ((value[i] == delim) &&
1519 value[i+1] == delim)
1520 /* skip the second deliminator */
1521 i++;
1522 }
1523 vol->password[j] = '\0';
1524 break;
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001525 case Opt_blank_ip:
1526 vol->UNCip = NULL;
1527 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001528 case Opt_ip:
1529 string = match_strdup(args);
1530 if (string == NULL)
1531 goto out_nomem;
1532
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001533 if (strnlen(string, INET6_ADDRSTRLEN) >
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001534 INET6_ADDRSTRLEN) {
1535 printk(KERN_WARNING "CIFS: ip address "
1536 "too long\n");
1537 goto cifs_parse_mount_err;
1538 }
1539 vol->UNCip = kstrdup(string, GFP_KERNEL);
1540 if (!vol->UNCip) {
1541 printk(KERN_WARNING "CIFS: no memory "
1542 "for UNC IP\n");
1543 goto cifs_parse_mount_err;
1544 }
1545 break;
1546 case Opt_unc:
1547 string = match_strdup(args);
1548 if (string == NULL)
1549 goto out_nomem;
1550
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001551 temp_len = strnlen(string, 300);
1552 if (temp_len == 300) {
1553 printk(KERN_WARNING "CIFS: UNC name too long\n");
1554 goto cifs_parse_mount_err;
1555 }
1556
Sachin Prabhue4b41fb2012-04-04 01:58:56 +01001557 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
1558 if (vol->UNC == NULL) {
1559 printk(KERN_WARNING "CIFS: no memory for UNC\n");
1560 goto cifs_parse_mount_err;
1561 }
1562 strcpy(vol->UNC, string);
1563
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001564 if (strncmp(string, "//", 2) == 0) {
1565 vol->UNC[0] = '\\';
1566 vol->UNC[1] = '\\';
1567 } else if (strncmp(string, "\\\\", 2) != 0) {
1568 printk(KERN_WARNING "CIFS: UNC Path does not "
1569 "begin with // or \\\\\n");
1570 goto cifs_parse_mount_err;
1571 }
1572
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001573 break;
1574 case Opt_domain:
1575 string = match_strdup(args);
1576 if (string == NULL)
1577 goto out_nomem;
1578
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001579 if (strnlen(string, 256) == 256) {
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001580 printk(KERN_WARNING "CIFS: domain name too"
1581 " long\n");
1582 goto cifs_parse_mount_err;
1583 }
1584
1585 vol->domainname = kstrdup(string, GFP_KERNEL);
1586 if (!vol->domainname) {
1587 printk(KERN_WARNING "CIFS: no memory "
1588 "for domainname\n");
1589 goto cifs_parse_mount_err;
1590 }
1591 cFYI(1, "Domain name set");
1592 break;
1593 case Opt_srcaddr:
1594 string = match_strdup(args);
1595 if (string == NULL)
1596 goto out_nomem;
1597
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001598 if (!cifs_convert_address(
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001599 (struct sockaddr *)&vol->srcaddr,
1600 string, strlen(string))) {
1601 printk(KERN_WARNING "CIFS: Could not parse"
1602 " srcaddr: %s\n", string);
1603 goto cifs_parse_mount_err;
1604 }
1605 break;
1606 case Opt_prefixpath:
1607 string = match_strdup(args);
1608 if (string == NULL)
1609 goto out_nomem;
1610
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001611 temp_len = strnlen(string, 1024);
1612 if (string[0] != '/')
1613 temp_len++; /* missing leading slash */
1614 if (temp_len > 1024) {
1615 printk(KERN_WARNING "CIFS: prefix too long\n");
1616 goto cifs_parse_mount_err;
1617 }
1618
1619 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1620 if (vol->prepath == NULL) {
1621 printk(KERN_WARNING "CIFS: no memory "
1622 "for path prefix\n");
1623 goto cifs_parse_mount_err;
1624 }
1625
1626 if (string[0] != '/') {
1627 vol->prepath[0] = '/';
1628 strcpy(vol->prepath+1, string);
1629 } else
1630 strcpy(vol->prepath, string);
1631
1632 break;
1633 case Opt_iocharset:
1634 string = match_strdup(args);
1635 if (string == NULL)
1636 goto out_nomem;
1637
Sachin Prabhu4fe9e962012-04-10 18:12:27 +01001638 if (strnlen(string, 1024) >= 65) {
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001639 printk(KERN_WARNING "CIFS: iocharset name "
1640 "too long.\n");
1641 goto cifs_parse_mount_err;
1642 }
1643
1644 if (strnicmp(string, "default", 7) != 0) {
1645 vol->iocharset = kstrdup(string,
1646 GFP_KERNEL);
1647 if (!vol->iocharset) {
1648 printk(KERN_WARNING "CIFS: no memory"
1649 "for charset\n");
1650 goto cifs_parse_mount_err;
1651 }
1652 }
1653 /* if iocharset not set then load_nls_default
1654 * is used by caller
1655 */
1656 cFYI(1, "iocharset set to %s", string);
1657 break;
1658 case Opt_sockopt:
1659 string = match_strdup(args);
1660 if (string == NULL)
1661 goto out_nomem;
1662
Jeff Layton67c1f522012-09-18 16:20:36 -07001663 if (strnicmp(string, "TCP_NODELAY", 11) == 0) {
1664 printk(KERN_WARNING "CIFS: the "
1665 "sockopt=TCP_NODELAY option has been "
1666 "deprecated and will be removed "
1667 "in 3.9\n");
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001668 vol->sockopt_tcp_nodelay = 1;
Jeff Layton67c1f522012-09-18 16:20:36 -07001669 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001670 break;
1671 case Opt_netbiosname:
1672 string = match_strdup(args);
1673 if (string == NULL)
1674 goto out_nomem;
1675
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001676 memset(vol->source_rfc1001_name, 0x20,
1677 RFC1001_NAME_LEN);
1678 /*
1679 * FIXME: are there cases in which a comma can
1680 * be valid in workstation netbios name (and
1681 * need special handling)?
1682 */
1683 for (i = 0; i < RFC1001_NAME_LEN; i++) {
1684 /* don't ucase netbiosname for user */
1685 if (string[i] == 0)
1686 break;
1687 vol->source_rfc1001_name[i] = string[i];
1688 }
1689 /* The string has 16th byte zero still from
1690 * set at top of the function
1691 */
1692 if (i == RFC1001_NAME_LEN && string[i] != 0)
1693 printk(KERN_WARNING "CIFS: netbiosname"
1694 " longer than 15 truncated.\n");
1695
1696 break;
1697 case Opt_servern:
1698 /* servernetbiosname specified override *SMBSERVER */
1699 string = match_strdup(args);
1700 if (string == NULL)
1701 goto out_nomem;
1702
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001703 /* last byte, type, is 0x20 for servr type */
1704 memset(vol->target_rfc1001_name, 0x20,
1705 RFC1001_NAME_LEN_WITH_NULL);
1706
1707 /* BB are there cases in which a comma can be
1708 valid in this workstation netbios name
1709 (and need special handling)? */
1710
1711 /* user or mount helper must uppercase the
1712 netbios name */
1713 for (i = 0; i < 15; i++) {
1714 if (string[i] == 0)
1715 break;
1716 vol->target_rfc1001_name[i] = string[i];
1717 }
1718 /* The string has 16th byte zero still from
1719 set at top of the function */
1720 if (i == RFC1001_NAME_LEN && string[i] != 0)
1721 printk(KERN_WARNING "CIFS: server net"
1722 "biosname longer than 15 truncated.\n");
1723 break;
1724 case Opt_ver:
1725 string = match_strdup(args);
1726 if (string == NULL)
1727 goto out_nomem;
1728
Jeff Layton5249af32012-05-15 12:04:03 -04001729 if (strnicmp(string, "1", 1) == 0) {
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001730 /* This is the default */
1731 break;
1732 }
1733 /* For all other value, error */
1734 printk(KERN_WARNING "CIFS: Invalid version"
1735 " specified\n");
Sean Finneyb9468452011-04-11 13:19:32 +00001736 goto cifs_parse_mount_err;
Jeff Layton23db65f2012-05-15 12:20:51 -04001737 case Opt_vers:
1738 string = match_strdup(args);
1739 if (string == NULL)
1740 goto out_nomem;
1741
1742 if (cifs_parse_smb_version(string, vol) != 0)
1743 goto cifs_parse_mount_err;
1744 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001745 case Opt_sec:
1746 string = match_strdup(args);
1747 if (string == NULL)
1748 goto out_nomem;
1749
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001750 if (cifs_parse_security_flavors(string, vol) != 0)
1751 goto cifs_parse_mount_err;
1752 break;
Jeff Layton15b6a472012-05-16 07:50:15 -04001753 case Opt_cache:
1754 string = match_strdup(args);
1755 if (string == NULL)
1756 goto out_nomem;
1757
1758 if (cifs_parse_cache_flavor(string, vol) != 0)
1759 goto cifs_parse_mount_err;
1760 break;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001761 default:
Jeff Laytond8162552012-03-23 14:40:56 -04001762 /*
1763 * An option we don't recognize. Save it off for later
1764 * if we haven't already found one
1765 */
1766 if (!invalid)
1767 invalid = data;
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001768 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001770 /* Free up any allocated string */
1771 kfree(string);
1772 string = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 }
Jeff Layton0eb8a132010-10-06 19:51:12 -04001774
Jeff Laytond8162552012-03-23 14:40:56 -04001775 if (!sloppy && invalid) {
1776 printk(KERN_ERR "CIFS: Unknown mount option \"%s\"\n", invalid);
1777 goto cifs_parse_mount_err;
1778 }
1779
Jeff Layton8a8798a2012-01-17 16:09:15 -05001780#ifndef CONFIG_KEYS
1781 /* Muliuser mounts require CONFIG_KEYS support */
1782 if (vol->multiuser) {
1783 cERROR(1, "Multiuser mounts require kernels with "
1784 "CONFIG_KEYS enabled.");
Sean Finneyb9468452011-04-11 13:19:32 +00001785 goto cifs_parse_mount_err;
Jeff Layton0eb8a132010-10-06 19:51:12 -04001786 }
Jeff Layton8a8798a2012-01-17 16:09:15 -05001787#endif
Jeff Layton0eb8a132010-10-06 19:51:12 -04001788
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 vol->UNCip = &vol->UNC[2];
1791
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001792 if (uid_specified)
1793 vol->override_uid = override_uid;
1794 else if (override_uid == 1)
1795 printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
1796 "specified with no uid= option.\n");
1797
1798 if (gid_specified)
1799 vol->override_gid = override_gid;
1800 else if (override_gid == 1)
1801 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
1802 "specified with no gid= option.\n");
1803
Sean Finneyb9468452011-04-11 13:19:32 +00001804 kfree(mountdata_copy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 return 0;
Sean Finneyb9468452011-04-11 13:19:32 +00001806
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001807out_nomem:
1808 printk(KERN_WARNING "Could not allocate temporary buffer\n");
Sean Finneyb9468452011-04-11 13:19:32 +00001809cifs_parse_mount_err:
Sachin Prabhu8830d7e2012-03-23 14:40:56 -04001810 kfree(string);
Sean Finneyb9468452011-04-11 13:19:32 +00001811 kfree(mountdata_copy);
1812 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813}
1814
Ben Greear3eb9a882010-09-01 17:06:02 -07001815/** Returns true if srcaddr isn't specified and rhs isn't
1816 * specified, or if srcaddr is specified and
1817 * matches the IP address of the rhs argument.
1818 */
Jeff Layton45151482010-07-06 20:43:02 -04001819static bool
Ben Greear3eb9a882010-09-01 17:06:02 -07001820srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
1821{
1822 switch (srcaddr->sa_family) {
1823 case AF_UNSPEC:
1824 return (rhs->sa_family == AF_UNSPEC);
1825 case AF_INET: {
1826 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1827 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1828 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1829 }
1830 case AF_INET6: {
1831 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1832 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
1833 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1834 }
1835 default:
1836 WARN_ON(1);
1837 return false; /* don't expect to be here */
1838 }
1839}
1840
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001841/*
1842 * If no port is specified in addr structure, we try to match with 445 port
1843 * and if it fails - with 139 ports. It should be called only if address
1844 * families of server and addr are equal.
1845 */
1846static bool
1847match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
1848{
Steve French6da97912011-03-13 18:55:55 +00001849 __be16 port, *sport;
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001850
1851 switch (addr->sa_family) {
1852 case AF_INET:
1853 sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
1854 port = ((struct sockaddr_in *) addr)->sin_port;
1855 break;
1856 case AF_INET6:
1857 sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
1858 port = ((struct sockaddr_in6 *) addr)->sin6_port;
1859 break;
1860 default:
1861 WARN_ON(1);
1862 return false;
1863 }
1864
1865 if (!port) {
1866 port = htons(CIFS_PORT);
1867 if (port == *sport)
1868 return true;
1869
1870 port = htons(RFC1001_PORT);
1871 }
1872
1873 return port == *sport;
1874}
Ben Greear3eb9a882010-09-01 17:06:02 -07001875
1876static bool
1877match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1878 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879{
Jeff Layton45151482010-07-06 20:43:02 -04001880 switch (addr->sa_family) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001881 case AF_INET: {
1882 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1883 struct sockaddr_in *srv_addr4 =
1884 (struct sockaddr_in *)&server->dstaddr;
1885
1886 if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
Jeff Layton45151482010-07-06 20:43:02 -04001887 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001888 break;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001889 }
1890 case AF_INET6: {
1891 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1892 struct sockaddr_in6 *srv_addr6 =
1893 (struct sockaddr_in6 *)&server->dstaddr;
1894
Jeff Layton45151482010-07-06 20:43:02 -04001895 if (!ipv6_addr_equal(&addr6->sin6_addr,
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001896 &srv_addr6->sin6_addr))
Jeff Layton45151482010-07-06 20:43:02 -04001897 return false;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001898 if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
Jeff Layton45151482010-07-06 20:43:02 -04001899 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001900 break;
1901 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001902 default:
1903 WARN_ON(1);
1904 return false; /* don't expect to be here */
1905 }
Jeff Layton45151482010-07-06 20:43:02 -04001906
Ben Greear3eb9a882010-09-01 17:06:02 -07001907 if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
1908 return false;
1909
Jeff Layton45151482010-07-06 20:43:02 -04001910 return true;
1911}
1912
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001913static bool
1914match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
1915{
1916 unsigned int secFlags;
1917
1918 if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
1919 secFlags = vol->secFlg;
1920 else
1921 secFlags = global_secflags | vol->secFlg;
1922
1923 switch (server->secType) {
1924 case LANMAN:
1925 if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
1926 return false;
1927 break;
1928 case NTLMv2:
1929 if (!(secFlags & CIFSSEC_MAY_NTLMV2))
1930 return false;
1931 break;
1932 case NTLM:
1933 if (!(secFlags & CIFSSEC_MAY_NTLM))
1934 return false;
1935 break;
1936 case Kerberos:
1937 if (!(secFlags & CIFSSEC_MAY_KRB5))
1938 return false;
1939 break;
1940 case RawNTLMSSP:
1941 if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
1942 return false;
1943 break;
1944 default:
1945 /* shouldn't happen */
1946 return false;
1947 }
1948
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001949 /* now check if signing mode is acceptable */
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001950 if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
Steve French96daf2b2011-05-27 04:34:02 +00001951 (server->sec_mode & SECMODE_SIGN_REQUIRED))
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001952 return false;
1953 else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
Steve French96daf2b2011-05-27 04:34:02 +00001954 (server->sec_mode &
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001955 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
1956 return false;
1957
1958 return true;
1959}
1960
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001961static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr,
1962 struct smb_vol *vol)
1963{
Jeff Layton23db65f2012-05-15 12:20:51 -04001964 if ((server->vals != vol->vals) || (server->ops != vol->ops))
1965 return 0;
1966
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001967 if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
1968 return 0;
1969
1970 if (!match_address(server, addr,
1971 (struct sockaddr *)&vol->srcaddr))
1972 return 0;
1973
1974 if (!match_port(server, addr))
1975 return 0;
1976
1977 if (!match_security(server, vol))
1978 return 0;
1979
1980 return 1;
1981}
1982
Jeff Layton45151482010-07-06 20:43:02 -04001983static struct TCP_Server_Info *
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001984cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
Jeff Layton45151482010-07-06 20:43:02 -04001985{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001986 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301988 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001989 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001990 if (!match_server(server, addr, vol))
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001991 continue;
1992
Jeff Laytone7ddee92008-11-14 13:44:38 -05001993 ++server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301994 spin_unlock(&cifs_tcp_ses_lock);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001995 cFYI(1, "Existing tcp session with server found");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001996 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301998 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return NULL;
2000}
2001
Jeff Layton14fbf502008-11-14 13:53:46 -05002002static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05002003cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004{
Jeff Laytone7ddee92008-11-14 13:44:38 -05002005 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302007 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002008 if (--server->srv_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302009 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002010 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 }
Steve Frenchdea570e02008-05-06 22:05:51 +00002012
Rob Landleyf1d0c992011-01-22 15:44:05 -06002013 put_net(cifs_net_ns(server));
2014
Jeff Laytone7ddee92008-11-14 13:44:38 -05002015 list_del_init(&server->tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302016 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002017
Jeff Laytonc74093b2011-01-11 07:24:23 -05002018 cancel_delayed_work_sync(&server->echo);
2019
Jeff Laytone7ddee92008-11-14 13:44:38 -05002020 spin_lock(&GlobalMid_Lock);
2021 server->tcpStatus = CifsExiting;
2022 spin_unlock(&GlobalMid_Lock);
2023
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05002024 cifs_crypto_shash_release(server);
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05302025 cifs_fscache_release_client_cookie(server);
2026
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05002027 kfree(server->session_key.response);
2028 server->session_key.response = NULL;
2029 server->session_key.len = 0;
2030
Jeff Laytone7ddee92008-11-14 13:44:38 -05002031 task = xchg(&server->tsk, NULL);
2032 if (task)
2033 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034}
2035
Jeff Layton63c038c2008-12-01 18:41:46 -05002036static struct TCP_Server_Info *
2037cifs_get_tcp_session(struct smb_vol *volume_info)
2038{
2039 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05002040 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05002041 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
2042 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
2043 int rc;
2044
Jeff Laytona9ac49d2009-01-22 14:43:21 -05002045 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05002046
Joe Perchesb6b38f72010-04-21 03:50:45 +00002047 cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04002048
Jeff Layton63c038c2008-12-01 18:41:46 -05002049 if (volume_info->UNCip && volume_info->UNC) {
Jeff Layton50d97162010-07-06 20:43:01 -04002050 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
2051 volume_info->UNCip,
David Howells67b76262010-07-22 18:33:01 +01002052 strlen(volume_info->UNCip),
Jeff Layton50d97162010-07-06 20:43:01 -04002053 volume_info->port);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04002054 if (!rc) {
Jeff Layton63c038c2008-12-01 18:41:46 -05002055 /* we failed translating address */
2056 rc = -EINVAL;
2057 goto out_err;
2058 }
Jeff Layton63c038c2008-12-01 18:41:46 -05002059 } else if (volume_info->UNCip) {
2060 /* BB using ip addr as tcp_ses name to connect to the
2061 DFS root below */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002062 cERROR(1, "Connecting to DFS root not implemented yet");
Jeff Layton63c038c2008-12-01 18:41:46 -05002063 rc = -EINVAL;
2064 goto out_err;
2065 } else /* which tcp_sess DFS root would we conect to */ {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002066 cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
2067 "unc=//192.168.1.100/public) specified");
Jeff Layton63c038c2008-12-01 18:41:46 -05002068 rc = -EINVAL;
2069 goto out_err;
2070 }
2071
2072 /* see if we already have a matching tcp_ses */
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04002073 tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002074 if (tcp_ses)
2075 return tcp_ses;
2076
2077 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2078 if (!tcp_ses) {
2079 rc = -ENOMEM;
2080 goto out_err;
2081 }
2082
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05002083 rc = cifs_crypto_shash_allocate(tcp_ses);
2084 if (rc) {
2085 cERROR(1, "could not setup hash structures rc %d", rc);
2086 goto out_err;
2087 }
2088
Jeff Layton23db65f2012-05-15 12:20:51 -04002089 tcp_ses->ops = volume_info->ops;
2090 tcp_ses->vals = volume_info->vals;
Rob Landleyf1d0c992011-01-22 15:44:05 -06002091 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
Jeff Layton63c038c2008-12-01 18:41:46 -05002092 tcp_ses->hostname = extract_hostname(volume_info->UNC);
2093 if (IS_ERR(tcp_ses->hostname)) {
2094 rc = PTR_ERR(tcp_ses->hostname);
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05002095 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05002096 }
2097
2098 tcp_ses->noblocksnd = volume_info->noblocksnd;
2099 tcp_ses->noautotune = volume_info->noautotune;
Steve French6a5fa2362010-01-01 01:28:43 +00002100 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +03002101 tcp_ses->in_flight = 0;
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04002102 tcp_ses->credits = 1;
Jeff Layton63c038c2008-12-01 18:41:46 -05002103 init_waitqueue_head(&tcp_ses->response_q);
2104 init_waitqueue_head(&tcp_ses->request_q);
2105 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
2106 mutex_init(&tcp_ses->srv_mutex);
2107 memcpy(tcp_ses->workstation_RFC1001_name,
2108 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
2109 memcpy(tcp_ses->server_RFC1001_name,
2110 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05002111 tcp_ses->session_estab = false;
Jeff Layton63c038c2008-12-01 18:41:46 -05002112 tcp_ses->sequence_number = 0;
Steve Frenchfda35942011-01-20 18:06:34 +00002113 tcp_ses->lstrp = jiffies;
Jeff Layton58fa0152012-05-01 17:41:16 -04002114 spin_lock_init(&tcp_ses->req_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05002115 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
2116 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
Jeff Laytonc74093b2011-01-11 07:24:23 -05002117 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
Jeff Layton63c038c2008-12-01 18:41:46 -05002118
2119 /*
2120 * at this point we are the only ones with the pointer
2121 * to the struct since the kernel thread not created yet
2122 * no need to spinlock this init of tcpStatus or srv_count
2123 */
2124 tcp_ses->tcpStatus = CifsNew;
Ben Greear3eb9a882010-09-01 17:06:02 -07002125 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
2126 sizeof(tcp_ses->srcaddr));
Jeff Layton63c038c2008-12-01 18:41:46 -05002127 ++tcp_ses->srv_count;
2128
Jeff Laytona9ac49d2009-01-22 14:43:21 -05002129 if (addr.ss_family == AF_INET6) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002130 cFYI(1, "attempting ipv6 connect");
Jeff Layton63c038c2008-12-01 18:41:46 -05002131 /* BB should we allow ipv6 on port 139? */
2132 /* other OS never observed in Wild doing 139 with v6 */
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002133 memcpy(&tcp_ses->dstaddr, sin_server6,
2134 sizeof(struct sockaddr_in6));
2135 } else
2136 memcpy(&tcp_ses->dstaddr, sin_server,
2137 sizeof(struct sockaddr_in));
2138
2139 rc = ip_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05002140 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002141 cERROR(1, "Error connecting to socket. Aborting operation");
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05002142 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05002143 }
2144
2145 /*
2146 * since we're in a cifs function already, we know that
2147 * this will succeed. No need for try_module_get().
2148 */
2149 __module_get(THIS_MODULE);
Al Viro7c97c202011-06-21 08:51:28 -04002150 tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
Jeff Layton63c038c2008-12-01 18:41:46 -05002151 tcp_ses, "cifsd");
2152 if (IS_ERR(tcp_ses->tsk)) {
2153 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002154 cERROR(1, "error %d create cifsd thread", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05002155 module_put(THIS_MODULE);
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05002156 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05002157 }
Steve Frenchfd88ce92011-04-12 01:01:14 +00002158 tcp_ses->tcpStatus = CifsNeedNegotiate;
Jeff Layton63c038c2008-12-01 18:41:46 -05002159
2160 /* thread spawned, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302161 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05002162 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302163 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05002164
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05302165 cifs_fscache_get_client_cookie(tcp_ses);
2166
Jeff Laytonc74093b2011-01-11 07:24:23 -05002167 /* queue echo request delayed work */
Jeff Laytonda472fc2012-03-23 14:40:53 -04002168 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
Jeff Laytonc74093b2011-01-11 07:24:23 -05002169
Jeff Layton63c038c2008-12-01 18:41:46 -05002170 return tcp_ses;
2171
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05002172out_err_crypto_release:
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05002173 cifs_crypto_shash_release(tcp_ses);
2174
Rob Landleyf1d0c992011-01-22 15:44:05 -06002175 put_net(cifs_net_ns(tcp_ses));
2176
Jeff Layton63c038c2008-12-01 18:41:46 -05002177out_err:
2178 if (tcp_ses) {
Steve French8347a5c2009-10-06 18:31:29 +00002179 if (!IS_ERR(tcp_ses->hostname))
2180 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05002181 if (tcp_ses->ssocket)
2182 sock_release(tcp_ses->ssocket);
2183 kfree(tcp_ses);
2184 }
2185 return ERR_PTR(rc);
2186}
2187
Steve French96daf2b2011-05-27 04:34:02 +00002188static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002189{
2190 switch (ses->server->secType) {
2191 case Kerberos:
2192 if (vol->cred_uid != ses->cred_uid)
2193 return 0;
2194 break;
2195 default:
Jeff Layton04febab2012-01-17 16:09:15 -05002196 /* NULL username means anonymous session */
2197 if (ses->user_name == NULL) {
2198 if (!vol->nullauth)
2199 return 0;
2200 break;
2201 }
2202
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002203 /* anything else takes username/password */
Jeff Layton04febab2012-01-17 16:09:15 -05002204 if (strncmp(ses->user_name,
2205 vol->username ? vol->username : "",
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002206 MAX_USERNAME_SIZE))
2207 return 0;
2208 if (strlen(vol->username) != 0 &&
2209 ses->password != NULL &&
2210 strncmp(ses->password,
2211 vol->password ? vol->password : "",
2212 MAX_PASSWORD_SIZE))
2213 return 0;
2214 }
2215 return 1;
2216}
2217
Steve French96daf2b2011-05-27 04:34:02 +00002218static struct cifs_ses *
Jeff Layton4ff67b72010-07-06 20:43:02 -04002219cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220{
Steve French96daf2b2011-05-27 04:34:02 +00002221 struct cifs_ses *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302223 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04002224 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002225 if (!match_session(ses, vol))
2226 continue;
Jeff Layton14fbf502008-11-14 13:53:46 -05002227 ++ses->ses_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302228 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05002229 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302231 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return NULL;
2233}
2234
Jeff Layton14fbf502008-11-14 13:53:46 -05002235static void
Steve French96daf2b2011-05-27 04:34:02 +00002236cifs_put_smb_ses(struct cifs_ses *ses)
Jeff Layton14fbf502008-11-14 13:53:46 -05002237{
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04002238 unsigned int xid;
Jeff Layton14fbf502008-11-14 13:53:46 -05002239 struct TCP_Server_Info *server = ses->server;
2240
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04002241 cFYI(1, "%s: ses_count=%d", __func__, ses->ses_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302242 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05002243 if (--ses->ses_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302244 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05002245 return;
2246 }
2247
2248 list_del_init(&ses->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302249 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05002250
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04002251 if (ses->status == CifsGood && server->ops->logoff) {
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002252 xid = get_xid();
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04002253 server->ops->logoff(xid, ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002254 _free_xid(xid);
Jeff Layton14fbf502008-11-14 13:53:46 -05002255 }
2256 sesInfoFree(ses);
2257 cifs_put_tcp_session(server);
2258}
2259
Jeff Layton8a8798a2012-01-17 16:09:15 -05002260#ifdef CONFIG_KEYS
2261
2262/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */
2263#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1)
2264
2265/* Populate username and pw fields from keyring if possible */
2266static int
2267cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
2268{
2269 int rc = 0;
2270 char *desc, *delim, *payload;
2271 ssize_t len;
2272 struct key *key;
2273 struct TCP_Server_Info *server = ses->server;
2274 struct sockaddr_in *sa;
2275 struct sockaddr_in6 *sa6;
2276 struct user_key_payload *upayload;
2277
2278 desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
2279 if (!desc)
2280 return -ENOMEM;
2281
2282 /* try to find an address key first */
2283 switch (server->dstaddr.ss_family) {
2284 case AF_INET:
2285 sa = (struct sockaddr_in *)&server->dstaddr;
2286 sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
2287 break;
2288 case AF_INET6:
2289 sa6 = (struct sockaddr_in6 *)&server->dstaddr;
2290 sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
2291 break;
2292 default:
2293 cFYI(1, "Bad ss_family (%hu)", server->dstaddr.ss_family);
2294 rc = -EINVAL;
2295 goto out_err;
2296 }
2297
2298 cFYI(1, "%s: desc=%s", __func__, desc);
2299 key = request_key(&key_type_logon, desc, "");
2300 if (IS_ERR(key)) {
2301 if (!ses->domainName) {
2302 cFYI(1, "domainName is NULL");
2303 rc = PTR_ERR(key);
2304 goto out_err;
2305 }
2306
2307 /* didn't work, try to find a domain key */
2308 sprintf(desc, "cifs:d:%s", ses->domainName);
2309 cFYI(1, "%s: desc=%s", __func__, desc);
2310 key = request_key(&key_type_logon, desc, "");
2311 if (IS_ERR(key)) {
2312 rc = PTR_ERR(key);
2313 goto out_err;
2314 }
2315 }
2316
2317 down_read(&key->sem);
2318 upayload = key->payload.data;
2319 if (IS_ERR_OR_NULL(upayload)) {
Jeff Layton4edc53c2012-02-07 06:30:51 -05002320 rc = upayload ? PTR_ERR(upayload) : -EINVAL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05002321 goto out_key_put;
2322 }
2323
2324 /* find first : in payload */
2325 payload = (char *)upayload->data;
2326 delim = strnchr(payload, upayload->datalen, ':');
2327 cFYI(1, "payload=%s", payload);
2328 if (!delim) {
2329 cFYI(1, "Unable to find ':' in payload (datalen=%d)",
2330 upayload->datalen);
2331 rc = -EINVAL;
2332 goto out_key_put;
2333 }
2334
2335 len = delim - payload;
2336 if (len > MAX_USERNAME_SIZE || len <= 0) {
Randy Dunlap000f9bb2012-01-30 19:50:01 -08002337 cFYI(1, "Bad value from username search (len=%zd)", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05002338 rc = -EINVAL;
2339 goto out_key_put;
2340 }
2341
2342 vol->username = kstrndup(payload, len, GFP_KERNEL);
2343 if (!vol->username) {
Randy Dunlap000f9bb2012-01-30 19:50:01 -08002344 cFYI(1, "Unable to allocate %zd bytes for username", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05002345 rc = -ENOMEM;
2346 goto out_key_put;
2347 }
2348 cFYI(1, "%s: username=%s", __func__, vol->username);
2349
2350 len = key->datalen - (len + 1);
2351 if (len > MAX_PASSWORD_SIZE || len <= 0) {
Randy Dunlap000f9bb2012-01-30 19:50:01 -08002352 cFYI(1, "Bad len for password search (len=%zd)", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05002353 rc = -EINVAL;
2354 kfree(vol->username);
2355 vol->username = NULL;
2356 goto out_key_put;
2357 }
2358
2359 ++delim;
2360 vol->password = kstrndup(delim, len, GFP_KERNEL);
2361 if (!vol->password) {
Randy Dunlap000f9bb2012-01-30 19:50:01 -08002362 cFYI(1, "Unable to allocate %zd bytes for password", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05002363 rc = -ENOMEM;
2364 kfree(vol->username);
2365 vol->username = NULL;
2366 goto out_key_put;
2367 }
2368
2369out_key_put:
2370 up_read(&key->sem);
2371 key_put(key);
2372out_err:
2373 kfree(desc);
2374 cFYI(1, "%s: returning %d", __func__, rc);
2375 return rc;
2376}
2377#else /* ! CONFIG_KEYS */
2378static inline int
2379cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
2380 struct cifs_ses *ses __attribute__((unused)))
2381{
2382 return -ENOSYS;
2383}
2384#endif /* CONFIG_KEYS */
2385
Steve Frenchd9b94202011-04-12 01:24:57 +00002386static bool warned_on_ntlm; /* globals init to false automatically */
2387
Steve French96daf2b2011-05-27 04:34:02 +00002388static struct cifs_ses *
Jeff Layton36988c72010-04-24 07:57:43 -04002389cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
2390{
Pavel Shilovsky286170a2012-05-25 10:43:58 +04002391 int rc = -ENOMEM;
2392 unsigned int xid;
Steve French96daf2b2011-05-27 04:34:02 +00002393 struct cifs_ses *ses;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002394 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2395 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
Jeff Layton36988c72010-04-24 07:57:43 -04002396
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002397 xid = get_xid();
Jeff Layton36988c72010-04-24 07:57:43 -04002398
Jeff Layton4ff67b72010-07-06 20:43:02 -04002399 ses = cifs_find_smb_ses(server, volume_info);
Jeff Layton36988c72010-04-24 07:57:43 -04002400 if (ses) {
2401 cFYI(1, "Existing smb sess found (status=%d)", ses->status);
2402
Jeff Layton36988c72010-04-24 07:57:43 -04002403 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04002404 rc = cifs_negotiate_protocol(xid, ses);
2405 if (rc) {
2406 mutex_unlock(&ses->session_mutex);
2407 /* problem -- put our ses reference */
2408 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002409 free_xid(xid);
Jeff Layton198b5682010-04-24 07:57:48 -04002410 return ERR_PTR(rc);
2411 }
Jeff Layton36988c72010-04-24 07:57:43 -04002412 if (ses->need_reconnect) {
2413 cFYI(1, "Session needs reconnect");
2414 rc = cifs_setup_session(xid, ses,
2415 volume_info->local_nls);
2416 if (rc) {
2417 mutex_unlock(&ses->session_mutex);
2418 /* problem -- put our reference */
2419 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002420 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04002421 return ERR_PTR(rc);
2422 }
2423 }
2424 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04002425
2426 /* existing SMB ses has a server reference already */
2427 cifs_put_tcp_session(server);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002428 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04002429 return ses;
2430 }
2431
2432 cFYI(1, "Existing smb sess not found");
2433 ses = sesInfoAlloc();
2434 if (ses == NULL)
2435 goto get_ses_fail;
2436
2437 /* new SMB session uses our server ref */
2438 ses->server = server;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002439 if (server->dstaddr.ss_family == AF_INET6)
2440 sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04002441 else
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002442 sprintf(ses->serverName, "%pI4", &addr->sin_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04002443
Steve French8727c8a2011-02-25 01:11:56 -06002444 if (volume_info->username) {
2445 ses->user_name = kstrdup(volume_info->username, GFP_KERNEL);
2446 if (!ses->user_name)
2447 goto get_ses_fail;
2448 }
Jeff Layton36988c72010-04-24 07:57:43 -04002449
2450 /* volume_info->password freed at unmount */
2451 if (volume_info->password) {
2452 ses->password = kstrdup(volume_info->password, GFP_KERNEL);
2453 if (!ses->password)
2454 goto get_ses_fail;
2455 }
2456 if (volume_info->domainname) {
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05002457 ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL);
2458 if (!ses->domainName)
2459 goto get_ses_fail;
Jeff Layton36988c72010-04-24 07:57:43 -04002460 }
Jeff Layton3e4b3e12010-07-19 18:00:17 -04002461 ses->cred_uid = volume_info->cred_uid;
Jeff Layton36988c72010-04-24 07:57:43 -04002462 ses->linux_uid = volume_info->linux_uid;
Steve Frenchd9b94202011-04-12 01:24:57 +00002463
2464 /* ntlmv2 is much stronger than ntlm security, and has been broadly
2465 supported for many years, time to update default security mechanism */
2466 if ((volume_info->secFlg == 0) && warned_on_ntlm == false) {
2467 warned_on_ntlm = true;
2468 cERROR(1, "default security mechanism requested. The default "
2469 "security mechanism will be upgraded from ntlm to "
Steve French225de112012-01-03 23:08:24 -06002470 "ntlmv2 in kernel release 3.3");
Steve Frenchd9b94202011-04-12 01:24:57 +00002471 }
Jeff Layton36988c72010-04-24 07:57:43 -04002472 ses->overrideSecFlg = volume_info->secFlg;
2473
2474 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04002475 rc = cifs_negotiate_protocol(xid, ses);
2476 if (!rc)
2477 rc = cifs_setup_session(xid, ses, volume_info->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04002478 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00002479 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04002480 goto get_ses_fail;
2481
2482 /* success, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302483 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04002484 list_add(&ses->smb_ses_list, &server->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302485 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04002486
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002487 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04002488 return ses;
2489
2490get_ses_fail:
2491 sesInfoFree(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002492 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04002493 return ERR_PTR(rc);
2494}
2495
Steve French96daf2b2011-05-27 04:34:02 +00002496static int match_tcon(struct cifs_tcon *tcon, const char *unc)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002497{
2498 if (tcon->tidStatus == CifsExiting)
2499 return 0;
2500 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
2501 return 0;
2502 return 1;
2503}
2504
Steve French96daf2b2011-05-27 04:34:02 +00002505static struct cifs_tcon *
2506cifs_find_tcon(struct cifs_ses *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507{
2508 struct list_head *tmp;
Steve French96daf2b2011-05-27 04:34:02 +00002509 struct cifs_tcon *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302511 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002512 list_for_each(tmp, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +00002513 tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00002514 if (!match_tcon(tcon, unc))
Jeff Laytonf1987b42008-11-15 11:12:47 -05002515 continue;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002516 ++tcon->tc_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302517 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 return tcon;
2519 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302520 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 return NULL;
2522}
2523
Jeff Laytonf1987b42008-11-15 11:12:47 -05002524static void
Steve French96daf2b2011-05-27 04:34:02 +00002525cifs_put_tcon(struct cifs_tcon *tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002526{
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002527 unsigned int xid;
Steve French96daf2b2011-05-27 04:34:02 +00002528 struct cifs_ses *ses = tcon->ses;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002529
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04002530 cFYI(1, "%s: tc_count=%d", __func__, tcon->tc_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302531 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002532 if (--tcon->tc_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302533 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002534 return;
2535 }
2536
2537 list_del_init(&tcon->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302538 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002539
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002540 xid = get_xid();
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002541 if (ses->server->ops->tree_disconnect)
2542 ses->server->ops->tree_disconnect(xid, tcon);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002543 _free_xid(xid);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002544
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302545 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00002546 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002547 cifs_put_smb_ses(ses);
2548}
2549
Steve French96daf2b2011-05-27 04:34:02 +00002550static struct cifs_tcon *
2551cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
Jeff Laytond00c28d2010-04-24 07:57:44 -04002552{
2553 int rc, xid;
Steve French96daf2b2011-05-27 04:34:02 +00002554 struct cifs_tcon *tcon;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002555
2556 tcon = cifs_find_tcon(ses, volume_info->UNC);
2557 if (tcon) {
2558 cFYI(1, "Found match on UNC path");
2559 /* existing tcon already has a reference */
2560 cifs_put_smb_ses(ses);
2561 if (tcon->seal != volume_info->seal)
2562 cERROR(1, "transport encryption setting "
2563 "conflicts with existing tid");
2564 return tcon;
2565 }
2566
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002567 if (!ses->server->ops->tree_connect) {
2568 rc = -ENOSYS;
2569 goto out_fail;
2570 }
2571
Jeff Laytond00c28d2010-04-24 07:57:44 -04002572 tcon = tconInfoAlloc();
2573 if (tcon == NULL) {
2574 rc = -ENOMEM;
2575 goto out_fail;
2576 }
2577
2578 tcon->ses = ses;
2579 if (volume_info->password) {
2580 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
2581 if (!tcon->password) {
2582 rc = -ENOMEM;
2583 goto out_fail;
2584 }
2585 }
2586
2587 if (strchr(volume_info->UNC + 3, '\\') == NULL
2588 && strchr(volume_info->UNC + 3, '/') == NULL) {
2589 cERROR(1, "Missing share name");
2590 rc = -ENODEV;
2591 goto out_fail;
2592 }
2593
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002594 /*
2595 * BB Do we need to wrap session_mutex around this TCon call and Unix
2596 * SetFS as we do on SessSetup and reconnect?
2597 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002598 xid = get_xid();
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002599 rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon,
2600 volume_info->local_nls);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002601 free_xid(xid);
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002602 cFYI(1, "Tcon rc = %d", rc);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002603 if (rc)
2604 goto out_fail;
2605
2606 if (volume_info->nodfs) {
2607 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2608 cFYI(1, "DFS disabled (%d)", tcon->Flags);
2609 }
2610 tcon->seal = volume_info->seal;
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002611 /*
2612 * We can have only one retry value for a connection to a share so for
2613 * resources mounted more than once to the same server share the last
2614 * value passed in for the retry flag is used.
2615 */
Jeff Laytond00c28d2010-04-24 07:57:44 -04002616 tcon->retry = volume_info->retry;
2617 tcon->nocase = volume_info->nocase;
2618 tcon->local_lease = volume_info->local_lease;
Pavel Shilovsky233839b2012-09-19 06:22:45 -07002619 INIT_LIST_HEAD(&tcon->pending_opens);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002620
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302621 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002622 list_add(&tcon->tcon_list, &ses->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302623 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002624
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302625 cifs_fscache_get_super_cookie(tcon);
2626
Jeff Laytond00c28d2010-04-24 07:57:44 -04002627 return tcon;
2628
2629out_fail:
2630 tconInfoFree(tcon);
2631 return ERR_PTR(rc);
2632}
2633
Jeff Layton9d002df2010-10-06 19:51:11 -04002634void
2635cifs_put_tlink(struct tcon_link *tlink)
2636{
2637 if (!tlink || IS_ERR(tlink))
2638 return;
2639
2640 if (!atomic_dec_and_test(&tlink->tl_count) ||
2641 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
2642 tlink->tl_time = jiffies;
2643 return;
2644 }
2645
2646 if (!IS_ERR(tlink_tcon(tlink)))
2647 cifs_put_tcon(tlink_tcon(tlink));
2648 kfree(tlink);
2649 return;
2650}
Jeff Laytond00c28d2010-04-24 07:57:44 -04002651
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002652static inline struct tcon_link *
Pavel Shilovskycd518752011-06-09 12:58:53 +04002653cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
2654{
2655 return cifs_sb->master_tlink;
2656}
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002657
2658static int
2659compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2660{
2661 struct cifs_sb_info *old = CIFS_SB(sb);
2662 struct cifs_sb_info *new = mnt_data->cifs_sb;
2663
2664 if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
2665 return 0;
2666
2667 if ((old->mnt_cifs_flags & CIFS_MOUNT_MASK) !=
2668 (new->mnt_cifs_flags & CIFS_MOUNT_MASK))
2669 return 0;
2670
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002671 /*
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002672 * We want to share sb only if we don't specify an r/wsize or
2673 * specified r/wsize is greater than or equal to existing one.
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002674 */
2675 if (new->wsize && new->wsize < old->wsize)
2676 return 0;
2677
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002678 if (new->rsize && new->rsize < old->rsize)
2679 return 0;
2680
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002681 if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
2682 return 0;
2683
2684 if (old->mnt_file_mode != new->mnt_file_mode ||
2685 old->mnt_dir_mode != new->mnt_dir_mode)
2686 return 0;
2687
2688 if (strcmp(old->local_nls->charset, new->local_nls->charset))
2689 return 0;
2690
2691 if (old->actimeo != new->actimeo)
2692 return 0;
2693
2694 return 1;
2695}
2696
2697int
2698cifs_match_super(struct super_block *sb, void *data)
2699{
2700 struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
2701 struct smb_vol *volume_info;
2702 struct cifs_sb_info *cifs_sb;
2703 struct TCP_Server_Info *tcp_srv;
Steve French96daf2b2011-05-27 04:34:02 +00002704 struct cifs_ses *ses;
2705 struct cifs_tcon *tcon;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002706 struct tcon_link *tlink;
2707 struct sockaddr_storage addr;
2708 int rc = 0;
2709
2710 memset(&addr, 0, sizeof(struct sockaddr_storage));
2711
2712 spin_lock(&cifs_tcp_ses_lock);
2713 cifs_sb = CIFS_SB(sb);
2714 tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
2715 if (IS_ERR(tlink)) {
2716 spin_unlock(&cifs_tcp_ses_lock);
2717 return rc;
2718 }
2719 tcon = tlink_tcon(tlink);
2720 ses = tcon->ses;
2721 tcp_srv = ses->server;
2722
2723 volume_info = mnt_data->vol;
2724
2725 if (!volume_info->UNCip || !volume_info->UNC)
2726 goto out;
2727
2728 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
2729 volume_info->UNCip,
2730 strlen(volume_info->UNCip),
2731 volume_info->port);
2732 if (!rc)
2733 goto out;
2734
2735 if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
2736 !match_session(ses, volume_info) ||
2737 !match_tcon(tcon, volume_info->UNC)) {
2738 rc = 0;
2739 goto out;
2740 }
2741
2742 rc = compare_mount_options(sb, mnt_data);
2743out:
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002744 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf484b5d02011-07-11 10:16:34 -04002745 cifs_put_tlink(tlink);
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002746 return rc;
2747}
2748
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749int
Pavel Shilovskyb669f332012-05-27 20:21:53 +04002750get_dfs_path(const unsigned int xid, struct cifs_ses *ses, const char *old_path,
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002751 const struct nls_table *nls_codepage, unsigned int *num_referrals,
2752 struct dfs_info3_param **referrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753{
2754 char *temp_unc;
2755 int rc = 0;
2756
Pavel Shilovskyb669f332012-05-27 20:21:53 +04002757 if (!ses->server->ops->tree_connect || !ses->server->ops->get_dfs_refer)
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002758 return -ENOSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002760 *num_referrals = 0;
2761 *referrals = NULL;
2762
2763 if (ses->ipc_tid == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 temp_unc = kmalloc(2 /* for slashes */ +
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002765 strnlen(ses->serverName, SERVER_NAME_LEN_WITH_NULL * 2)
2766 + 1 + 4 /* slash IPC$ */ + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 if (temp_unc == NULL)
2768 return -ENOMEM;
2769 temp_unc[0] = '\\';
2770 temp_unc[1] = '\\';
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002771 strcpy(temp_unc + 2, ses->serverName);
2772 strcpy(temp_unc + 2 + strlen(ses->serverName), "\\IPC$");
2773 rc = ses->server->ops->tree_connect(xid, ses, temp_unc, NULL,
2774 nls_codepage);
2775 cFYI(1, "Tcon rc = %d ipc_tid = %d", rc, ses->ipc_tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 kfree(temp_unc);
2777 }
2778 if (rc == 0)
Pavel Shilovskyb669f332012-05-27 20:21:53 +04002779 rc = ses->server->ops->get_dfs_refer(xid, ses, old_path,
2780 referrals, num_referrals,
2781 nls_codepage, remap);
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002782 /*
2783 * BB - map targetUNCs to dfs_info3 structures, here or in
Pavel Shilovskyb669f332012-05-27 20:21:53 +04002784 * ses->server->ops->get_dfs_refer.
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002785 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
2787 return rc;
2788}
2789
Jeff Layton09e50d52008-07-23 10:11:19 -04002790#ifdef CONFIG_DEBUG_LOCK_ALLOC
2791static struct lock_class_key cifs_key[2];
2792static struct lock_class_key cifs_slock_key[2];
2793
2794static inline void
2795cifs_reclassify_socket4(struct socket *sock)
2796{
2797 struct sock *sk = sock->sk;
2798 BUG_ON(sock_owned_by_user(sk));
2799 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2800 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2801}
2802
2803static inline void
2804cifs_reclassify_socket6(struct socket *sock)
2805{
2806 struct sock *sk = sock->sk;
2807 BUG_ON(sock_owned_by_user(sk));
2808 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2809 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2810}
2811#else
2812static inline void
2813cifs_reclassify_socket4(struct socket *sock)
2814{
2815}
2816
2817static inline void
2818cifs_reclassify_socket6(struct socket *sock)
2819{
2820}
2821#endif
2822
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002824static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825{
Steve French50c2f752007-07-13 00:33:32 +00002826 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
Steve French50c2f752007-07-13 00:33:32 +00002828 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 /* mask a nibble at a time and encode */
2830 target[j] = 'A' + (0x0F & (source[i] >> 4));
2831 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002832 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
2834
2835}
2836
Ben Greear3eb9a882010-09-01 17:06:02 -07002837static int
2838bind_socket(struct TCP_Server_Info *server)
2839{
2840 int rc = 0;
2841 if (server->srcaddr.ss_family != AF_UNSPEC) {
2842 /* Bind to the specified local IP address */
2843 struct socket *socket = server->ssocket;
2844 rc = socket->ops->bind(socket,
2845 (struct sockaddr *) &server->srcaddr,
2846 sizeof(server->srcaddr));
2847 if (rc < 0) {
2848 struct sockaddr_in *saddr4;
2849 struct sockaddr_in6 *saddr6;
2850 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2851 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2852 if (saddr6->sin6_family == AF_INET6)
2853 cERROR(1, "cifs: "
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04002854 "Failed to bind to: %pI6c, error: %d",
Ben Greear3eb9a882010-09-01 17:06:02 -07002855 &saddr6->sin6_addr, rc);
2856 else
2857 cERROR(1, "cifs: "
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04002858 "Failed to bind to: %pI4, error: %d",
Ben Greear3eb9a882010-09-01 17:06:02 -07002859 &saddr4->sin_addr.s_addr, rc);
2860 }
2861 }
2862 return rc;
2863}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864
2865static int
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002866ip_rfc1001_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867{
2868 int rc = 0;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002869 /*
2870 * some servers require RFC1001 sessinit before sending
2871 * negprot - BB check reconnection in case where second
2872 * sessinit is sent but no second negprot
2873 */
2874 struct rfc1002_session_packet *ses_init_buf;
2875 struct smb_hdr *smb_buf;
2876 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2877 GFP_KERNEL);
2878 if (ses_init_buf) {
2879 ses_init_buf->trailer.session_req.called_len = 32;
2880
2881 if (server->server_RFC1001_name &&
2882 server->server_RFC1001_name[0] != 0)
2883 rfc1002mangle(ses_init_buf->trailer.
2884 session_req.called_name,
2885 server->server_RFC1001_name,
2886 RFC1001_NAME_LEN_WITH_NULL);
2887 else
2888 rfc1002mangle(ses_init_buf->trailer.
2889 session_req.called_name,
2890 DEFAULT_CIFS_CALLED_NAME,
2891 RFC1001_NAME_LEN_WITH_NULL);
2892
2893 ses_init_buf->trailer.session_req.calling_len = 32;
2894
2895 /*
2896 * calling name ends in null (byte 16) from old smb
2897 * convention.
2898 */
2899 if (server->workstation_RFC1001_name &&
2900 server->workstation_RFC1001_name[0] != 0)
2901 rfc1002mangle(ses_init_buf->trailer.
2902 session_req.calling_name,
2903 server->workstation_RFC1001_name,
2904 RFC1001_NAME_LEN_WITH_NULL);
2905 else
2906 rfc1002mangle(ses_init_buf->trailer.
2907 session_req.calling_name,
2908 "LINUX_CIFS_CLNT",
2909 RFC1001_NAME_LEN_WITH_NULL);
2910
2911 ses_init_buf->trailer.session_req.scope1 = 0;
2912 ses_init_buf->trailer.session_req.scope2 = 0;
2913 smb_buf = (struct smb_hdr *)ses_init_buf;
2914
2915 /* sizeof RFC1002_SESSION_REQUEST with no scope */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002916 smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002917 rc = smb_send(server, smb_buf, 0x44);
2918 kfree(ses_init_buf);
2919 /*
2920 * RFC1001 layer in at least one server
2921 * requires very short break before negprot
2922 * presumably because not expecting negprot
2923 * to follow so fast. This is a simple
2924 * solution that works without
2925 * complicating the code and causes no
2926 * significant slowing down on mount
2927 * for everyone else
2928 */
2929 usleep_range(1000, 2000);
2930 }
2931 /*
2932 * else the negprot may still work without this
2933 * even though malloc failed
2934 */
2935
2936 return rc;
2937}
2938
2939static int
2940generic_ip_connect(struct TCP_Server_Info *server)
2941{
2942 int rc = 0;
Steve French6da97912011-03-13 18:55:55 +00002943 __be16 sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002944 int slen, sfamily;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002945 struct socket *socket = server->ssocket;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002946 struct sockaddr *saddr;
2947
2948 saddr = (struct sockaddr *) &server->dstaddr;
2949
2950 if (server->dstaddr.ss_family == AF_INET6) {
2951 sport = ((struct sockaddr_in6 *) saddr)->sin6_port;
2952 slen = sizeof(struct sockaddr_in6);
2953 sfamily = AF_INET6;
2954 } else {
2955 sport = ((struct sockaddr_in *) saddr)->sin_port;
2956 slen = sizeof(struct sockaddr_in);
2957 sfamily = AF_INET;
2958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002960 if (socket == NULL) {
Rob Landleyf1d0c992011-01-22 15:44:05 -06002961 rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
2962 IPPROTO_TCP, &socket, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002964 cERROR(1, "Error %d creating socket", rc);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002965 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002968
2969 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002970 cFYI(1, "Socket created");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002971 server->ssocket = socket;
2972 socket->sk->sk_allocation = GFP_NOFS;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002973 if (sfamily == AF_INET6)
2974 cifs_reclassify_socket6(socket);
2975 else
2976 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 }
2978
Ben Greear3eb9a882010-09-01 17:06:02 -07002979 rc = bind_socket(server);
2980 if (rc < 0)
2981 return rc;
2982
Jeff Laytond5c56052008-12-01 18:42:33 -05002983 /*
2984 * Eventually check for other socket options to change from
2985 * the default. sock_setsockopt not used because it expects
2986 * user space buffer
2987 */
2988 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002989 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002990
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002991 /* make the bufsizes depend on wsize/rsize and max requests */
2992 if (server->noautotune) {
2993 if (socket->sk->sk_sndbuf < (200 * 1024))
2994 socket->sk->sk_sndbuf = 200 * 1024;
2995 if (socket->sk->sk_rcvbuf < (140 * 1024))
2996 socket->sk->sk_rcvbuf = 140 * 1024;
2997 }
2998
Steve French6a5fa2362010-01-01 01:28:43 +00002999 if (server->tcp_nodelay) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03003000 int val = 1;
Steve French6a5fa2362010-01-01 01:28:43 +00003001 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
3002 (char *)&val, sizeof(val));
3003 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003004 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00003005 }
3006
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03003007 cFYI(1, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
3008 socket->sk->sk_sndbuf,
3009 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
3010
Jeff Laytonee1b3ea2011-06-21 07:18:26 -04003011 rc = socket->ops->connect(socket, saddr, slen, 0);
3012 if (rc < 0) {
3013 cFYI(1, "Error %d connecting to server", rc);
3014 sock_release(socket);
3015 server->ssocket = NULL;
3016 return rc;
3017 }
3018
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03003019 if (sport == htons(RFC1001_PORT))
3020 rc = ip_rfc1001_connect(server);
Steve French50c2f752007-07-13 00:33:32 +00003021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 return rc;
3023}
3024
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03003025static int
3026ip_connect(struct TCP_Server_Info *server)
3027{
Steve French6da97912011-03-13 18:55:55 +00003028 __be16 *sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03003029 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
3030 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3031
3032 if (server->dstaddr.ss_family == AF_INET6)
3033 sport = &addr6->sin6_port;
3034 else
3035 sport = &addr->sin_port;
3036
3037 if (*sport == 0) {
3038 int rc;
3039
3040 /* try with 445 port at first */
3041 *sport = htons(CIFS_PORT);
3042
3043 rc = generic_ip_connect(server);
3044 if (rc >= 0)
3045 return rc;
3046
3047 /* if it failed, try with 139 port */
3048 *sport = htons(RFC1001_PORT);
3049 }
3050
3051 return generic_ip_connect(server);
3052}
3053
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003054void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
Al Viro2c6292a2011-06-17 09:05:48 -04003055 struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00003056{
3057 /* if we are reconnecting then should we check to see if
3058 * any requested capabilities changed locally e.g. via
3059 * remount but we can not do much about it here
3060 * if they have (even if we could detect it by the following)
3061 * Perhaps we could add a backpointer to array of sb from tcon
3062 * or if we change to make all sb to same share the same
3063 * sb as NFS - then we only have one backpointer to sb.
3064 * What if we wanted to mount the server share twice once with
3065 * and once without posixacls or posix paths? */
3066 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00003067
Steve Frenchc18c8422007-07-18 23:21:09 +00003068 if (vol_info && vol_info->no_linux_ext) {
3069 tcon->fsUnixInfo.Capability = 0;
3070 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003071 cFYI(1, "Linux protocol extensions disabled");
Steve Frenchc18c8422007-07-18 23:21:09 +00003072 return;
3073 } else if (vol_info)
3074 tcon->unix_ext = 1; /* Unix Extensions supported */
3075
3076 if (tcon->unix_ext == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003077 cFYI(1, "Unix extensions disabled so not set on reconnect");
Steve Frenchc18c8422007-07-18 23:21:09 +00003078 return;
3079 }
Steve French50c2f752007-07-13 00:33:32 +00003080
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003081 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00003082 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French6848b732011-05-26 18:38:54 +00003083 cFYI(1, "unix caps which server supports %lld", cap);
Steve French8af18972007-02-14 04:42:51 +00003084 /* check for reconnect case in which we do not
3085 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003086 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003087 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00003088 originally at mount time */
3089 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
3090 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00003091 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
3092 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003093 cERROR(1, "POSIXPATH support change");
Steve French8af18972007-02-14 04:42:51 +00003094 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00003095 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003096 cERROR(1, "possible reconnect error");
3097 cERROR(1, "server disabled POSIX path support");
Igor Mammedov11b6d642008-02-15 19:06:04 +00003098 }
Steve French8af18972007-02-14 04:42:51 +00003099 }
Steve French50c2f752007-07-13 00:33:32 +00003100
Steve French6848b732011-05-26 18:38:54 +00003101 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3102 cERROR(1, "per-share encryption not supported yet");
3103
Steve French8af18972007-02-14 04:42:51 +00003104 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00003105 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00003106 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00003107 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003108 cFYI(1, "negotiated posix acl support");
Al Viro2c6292a2011-06-17 09:05:48 -04003109 if (cifs_sb)
3110 cifs_sb->mnt_cifs_flags |=
3111 CIFS_MOUNT_POSIXACL;
Steve French8af18972007-02-14 04:42:51 +00003112 }
3113
Steve French75865f8c2007-06-24 18:30:48 +00003114 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00003115 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00003116 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003117 cFYI(1, "negotiate posix pathnames");
Al Viro2c6292a2011-06-17 09:05:48 -04003118 if (cifs_sb)
3119 cifs_sb->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00003120 CIFS_MOUNT_POSIX_PATHS;
3121 }
Steve French50c2f752007-07-13 00:33:32 +00003122
Joe Perchesb6b38f72010-04-21 03:50:45 +00003123 cFYI(1, "Negotiate caps 0x%x", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00003124#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00003125 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003126 cFYI(1, "FCNTL cap");
Steve French75865f8c2007-06-24 18:30:48 +00003127 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003128 cFYI(1, "EXTATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00003129 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003130 cFYI(1, "POSIX path cap");
Steve French75865f8c2007-06-24 18:30:48 +00003131 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003132 cFYI(1, "XATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00003133 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003134 cFYI(1, "POSIX ACL cap");
Steve French75865f8c2007-06-24 18:30:48 +00003135 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003136 cFYI(1, "very large read cap");
Steve French75865f8c2007-06-24 18:30:48 +00003137 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003138 cFYI(1, "very large write cap");
Steve French6848b732011-05-26 18:38:54 +00003139 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
3140 cFYI(1, "transport encryption cap");
3141 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3142 cFYI(1, "mandatory transport encryption cap");
Steve French8af18972007-02-14 04:42:51 +00003143#endif /* CIFS_DEBUG2 */
3144 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00003145 if (vol_info == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003146 cFYI(1, "resetting capabilities failed");
Steve French442aa312007-09-24 20:25:46 +00003147 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003148 cERROR(1, "Negotiating Unix capabilities "
Jeff Laytonac3aa2f2012-07-23 13:14:28 -04003149 "with the server failed. Consider "
3150 "mounting with the Unix Extensions "
3151 "disabled if problems are found "
Steve French5a44b312007-09-20 15:16:24 +00003152 "by specifying the nounix mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003153 "option.");
Steve French5a44b312007-09-20 15:16:24 +00003154
Steve French8af18972007-02-14 04:42:51 +00003155 }
3156 }
3157}
3158
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003159void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3160 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04003161{
Jeff Layton2de970f2010-10-06 19:51:12 -04003162 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
3163
Al Viro2ced6f62011-06-17 09:20:04 -04003164 spin_lock_init(&cifs_sb->tlink_tree_lock);
3165 cifs_sb->tlink_tree = RB_ROOT;
3166
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04003167 /*
Jeff Layton5eba8ab2011-10-19 15:30:26 -04003168 * Temporarily set r/wsize for matching superblock. If we end up using
3169 * new sb then client will later negotiate it downward if needed.
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04003170 */
Jeff Layton5eba8ab2011-10-19 15:30:26 -04003171 cifs_sb->rsize = pvolume_info->rsize;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04003172 cifs_sb->wsize = pvolume_info->wsize;
3173
Steve French3b795212008-11-13 19:45:32 +00003174 cifs_sb->mnt_uid = pvolume_info->linux_uid;
3175 cifs_sb->mnt_gid = pvolume_info->linux_gid;
3176 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
3177 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
Al Viro5206efd2011-07-26 03:22:14 -04003178 cFYI(1, "file mode: 0x%hx dir mode: 0x%hx",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003179 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
Steve French3b795212008-11-13 19:45:32 +00003180
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05303181 cifs_sb->actimeo = pvolume_info->actimeo;
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003182 cifs_sb->local_nls = pvolume_info->local_nls;
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05303183
Steve French3b795212008-11-13 19:45:32 +00003184 if (pvolume_info->noperm)
3185 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
3186 if (pvolume_info->setuids)
3187 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
3188 if (pvolume_info->server_ino)
3189 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
3190 if (pvolume_info->remap)
3191 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
3192 if (pvolume_info->no_xattr)
3193 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
3194 if (pvolume_info->sfu_emul)
3195 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
3196 if (pvolume_info->nobrl)
3197 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve Frenchbe652442009-02-23 15:21:59 +00003198 if (pvolume_info->nostrictsync)
Steve French4717bed2009-02-24 14:44:19 +00003199 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
Steve French13a6e422008-12-02 17:24:33 +00003200 if (pvolume_info->mand_lock)
3201 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00003202 if (pvolume_info->rwpidforward)
3203 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
Steve French3b795212008-11-13 19:45:32 +00003204 if (pvolume_info->cifs_acl)
3205 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Sachin Prabhu3c7c87f2012-04-24 15:28:14 +01003206 if (pvolume_info->backupuid_specified) {
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05003207 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
Sachin Prabhu3c7c87f2012-04-24 15:28:14 +01003208 cifs_sb->mnt_backupuid = pvolume_info->backupuid;
3209 }
3210 if (pvolume_info->backupgid_specified) {
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05003211 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
Sachin Prabhu3c7c87f2012-04-24 15:28:14 +01003212 cifs_sb->mnt_backupgid = pvolume_info->backupgid;
3213 }
Steve French3b795212008-11-13 19:45:32 +00003214 if (pvolume_info->override_uid)
3215 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
3216 if (pvolume_info->override_gid)
3217 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
3218 if (pvolume_info->dynperm)
3219 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05303220 if (pvolume_info->fsc)
3221 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
Jeff Layton0eb8a132010-10-06 19:51:12 -04003222 if (pvolume_info->multiuser)
3223 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
3224 CIFS_MOUNT_NO_PERM);
Pavel Shilovskyd39454f2011-01-24 14:16:35 -05003225 if (pvolume_info->strict_io)
3226 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
Steve French3b795212008-11-13 19:45:32 +00003227 if (pvolume_info->direct_io) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003228 cFYI(1, "mounting share using direct i/o");
Steve French3b795212008-11-13 19:45:32 +00003229 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
3230 }
Stefan Metzmacher736a3322010-07-30 14:56:00 +02003231 if (pvolume_info->mfsymlinks) {
3232 if (pvolume_info->sfu_emul) {
3233 cERROR(1, "mount option mfsymlinks ignored if sfu "
3234 "mount option is used");
3235 } else {
3236 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
3237 }
3238 }
Steve French3b795212008-11-13 19:45:32 +00003239
3240 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
Joe Perchesb6b38f72010-04-21 03:50:45 +00003241 cERROR(1, "mount option dynperm ignored if cifsacl "
3242 "mount option supported");
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04003243}
3244
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04003245static void
3246cleanup_volume_info_contents(struct smb_vol *volume_info)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003247{
Sean Finneyb9468452011-04-11 13:19:32 +00003248 kfree(volume_info->username);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003249 kzfree(volume_info->password);
Steve French13589c42011-08-18 04:41:55 +00003250 if (volume_info->UNCip != volume_info->UNC + 2)
3251 kfree(volume_info->UNCip);
Jesper Juhl95c75452011-08-27 18:58:34 +02003252 kfree(volume_info->UNC);
Sean Finneyb9468452011-04-11 13:19:32 +00003253 kfree(volume_info->domainname);
3254 kfree(volume_info->iocharset);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003255 kfree(volume_info->prepath);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003256}
3257
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04003258void
3259cifs_cleanup_volume_info(struct smb_vol *volume_info)
3260{
3261 if (!volume_info)
3262 return;
3263 cleanup_volume_info_contents(volume_info);
3264 kfree(volume_info);
3265}
3266
3267
Steve French2d6d5892009-04-09 00:36:44 +00003268#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003269/* build_path_to_root returns full path to root when
3270 * we do not have an exiting connection (tcon) */
3271static char *
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04003272build_unc_path_to_root(const struct smb_vol *vol,
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003273 const struct cifs_sb_info *cifs_sb)
3274{
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04003275 char *full_path, *pos;
3276 unsigned int pplen = vol->prepath ? strlen(vol->prepath) : 0;
3277 unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003278
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04003279 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003280 if (full_path == NULL)
3281 return ERR_PTR(-ENOMEM);
3282
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04003283 strncpy(full_path, vol->UNC, unc_len);
3284 pos = full_path + unc_len;
3285
3286 if (pplen) {
3287 strncpy(pos, vol->prepath, pplen);
3288 pos += pplen;
3289 }
3290
3291 *pos = '\0'; /* add trailing null */
Steve Frenchf87d39d2011-05-27 03:50:55 +00003292 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04003293 cFYI(1, "%s: full_path=%s", __func__, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003294 return full_path;
3295}
Sean Finneydd613942011-04-11 13:19:30 +00003296
3297/*
3298 * Perform a dfs referral query for a share and (optionally) prefix
3299 *
Sean Finney046462a2011-04-11 13:19:33 +00003300 * If a referral is found, cifs_sb->mountdata will be (re-)allocated
3301 * to a string containing updated options for the submount. Otherwise it
3302 * will be left untouched.
Sean Finneydd613942011-04-11 13:19:30 +00003303 *
3304 * Returns the rc from get_dfs_path to the caller, which can be used to
3305 * determine whether there were referrals.
3306 */
3307static int
Pavel Shilovskyb669f332012-05-27 20:21:53 +04003308expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
Sean Finneydd613942011-04-11 13:19:30 +00003309 struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
Sean Finney046462a2011-04-11 13:19:33 +00003310 int check_prefix)
Sean Finneydd613942011-04-11 13:19:30 +00003311{
3312 int rc;
3313 unsigned int num_referrals = 0;
3314 struct dfs_info3_param *referrals = NULL;
3315 char *full_path = NULL, *ref_path = NULL, *mdata = NULL;
3316
3317 full_path = build_unc_path_to_root(volume_info, cifs_sb);
3318 if (IS_ERR(full_path))
3319 return PTR_ERR(full_path);
3320
3321 /* For DFS paths, skip the first '\' of the UNC */
3322 ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
3323
Pavel Shilovskyb669f332012-05-27 20:21:53 +04003324 rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls,
Sean Finneydd613942011-04-11 13:19:30 +00003325 &num_referrals, &referrals,
3326 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
3327
3328 if (!rc && num_referrals > 0) {
3329 char *fake_devname = NULL;
3330
3331 mdata = cifs_compose_mount_options(cifs_sb->mountdata,
3332 full_path + 1, referrals,
3333 &fake_devname);
3334
3335 free_dfs_info_array(referrals, num_referrals);
Sean Finney046462a2011-04-11 13:19:33 +00003336
Sean Finneydd613942011-04-11 13:19:30 +00003337 if (IS_ERR(mdata)) {
3338 rc = PTR_ERR(mdata);
3339 mdata = NULL;
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04003340 } else {
3341 cleanup_volume_info_contents(volume_info);
3342 memset(volume_info, '\0', sizeof(*volume_info));
3343 rc = cifs_setup_volume_info(volume_info, mdata,
3344 fake_devname);
Sean Finneydd613942011-04-11 13:19:30 +00003345 }
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04003346 kfree(fake_devname);
3347 kfree(cifs_sb->mountdata);
Sean Finney046462a2011-04-11 13:19:33 +00003348 cifs_sb->mountdata = mdata;
Sean Finneydd613942011-04-11 13:19:30 +00003349 }
3350 kfree(full_path);
3351 return rc;
3352}
Steve French2d6d5892009-04-09 00:36:44 +00003353#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003354
Jeff Layton04db79b2011-07-06 08:10:38 -04003355static int
3356cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
3357 const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358{
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003359 int rc = 0;
Sean Finneydd613942011-04-11 13:19:30 +00003360
Jeff Layton04db79b2011-07-06 08:10:38 -04003361 if (cifs_parse_mount_options(mount_data, devname, volume_info))
3362 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Jeff Layton23db65f2012-05-15 12:20:51 -04003364
Jeff Layton7586b762008-12-01 18:41:49 -05003365 if (volume_info->nullauth) {
Jeff Layton04febab2012-01-17 16:09:15 -05003366 cFYI(1, "Anonymous login");
3367 kfree(volume_info->username);
3368 volume_info->username = NULL;
Jeff Layton7586b762008-12-01 18:41:49 -05003369 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 /* BB fixme parse for domain name here */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003371 cFYI(1, "Username: %s", volume_info->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08003373 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00003374 /* In userspace mount helper we can get user name from alternate
3375 locations such as env variables and files on disk */
Jeff Layton04db79b2011-07-06 08:10:38 -04003376 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 }
3378
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05003380 if (volume_info->iocharset == NULL) {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04003381 /* load_nls_default cannot return null */
3382 volume_info->local_nls = load_nls_default();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 } else {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04003384 volume_info->local_nls = load_nls(volume_info->iocharset);
3385 if (volume_info->local_nls == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003386 cERROR(1, "CIFS mount error: iocharset %s not found",
3387 volume_info->iocharset);
Jeff Layton04db79b2011-07-06 08:10:38 -04003388 return -ELIBACC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 }
3390 }
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003391
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003392 return rc;
Jeff Layton04db79b2011-07-06 08:10:38 -04003393}
3394
3395struct smb_vol *
3396cifs_get_volume_info(char *mount_data, const char *devname)
3397{
3398 int rc;
3399 struct smb_vol *volume_info;
3400
3401 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
3402 if (!volume_info)
3403 return ERR_PTR(-ENOMEM);
3404
3405 rc = cifs_setup_volume_info(volume_info, mount_data, devname);
3406 if (rc) {
3407 cifs_cleanup_volume_info(volume_info);
3408 volume_info = ERR_PTR(rc);
3409 }
3410
3411 return volume_info;
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003412}
3413
3414int
Al Viro2c6292a2011-06-17 09:05:48 -04003415cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003416{
Jeff Layton1daaae82012-03-21 06:30:40 -04003417 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003418 unsigned int xid;
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003419 struct cifs_ses *ses;
Steve French96daf2b2011-05-27 04:34:02 +00003420 struct cifs_tcon *tcon;
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003421 struct TCP_Server_Info *server;
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003422 char *full_path;
3423 struct tcon_link *tlink;
3424#ifdef CONFIG_CIFS_DFS_UPCALL
3425 int referral_walks_count = 0;
Jeff Layton20547492011-07-09 12:21:07 -04003426#endif
Al Virodd854462011-06-17 08:24:42 -04003427
3428 rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
3429 if (rc)
3430 return rc;
3431
Jeff Layton20547492011-07-09 12:21:07 -04003432#ifdef CONFIG_CIFS_DFS_UPCALL
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003433try_mount_again:
3434 /* cleanup activities if we're chasing a referral */
3435 if (referral_walks_count) {
3436 if (tcon)
3437 cifs_put_tcon(tcon);
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003438 else if (ses)
3439 cifs_put_smb_ses(ses);
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003440
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003441 free_xid(xid);
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003442 }
3443#endif
Jeff Layton1daaae82012-03-21 06:30:40 -04003444 rc = 0;
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003445 tcon = NULL;
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003446 ses = NULL;
3447 server = NULL;
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003448 full_path = NULL;
3449 tlink = NULL;
3450
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003451 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452
Jeff Layton63c038c2008-12-01 18:41:46 -05003453 /* get a reference to a tcp session */
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003454 server = cifs_get_tcp_session(volume_info);
3455 if (IS_ERR(server)) {
3456 rc = PTR_ERR(server);
Al Virodd854462011-06-17 08:24:42 -04003457 bdi_destroy(&cifs_sb->bdi);
Jeff Layton63c038c2008-12-01 18:41:46 -05003458 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 }
3460
Jeff Layton36988c72010-04-24 07:57:43 -04003461 /* get a reference to a SMB session */
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003462 ses = cifs_get_smb_ses(server, volume_info);
3463 if (IS_ERR(ses)) {
3464 rc = PTR_ERR(ses);
3465 ses = NULL;
Jeff Layton36988c72010-04-24 07:57:43 -04003466 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 }
Steve French50c2f752007-07-13 00:33:32 +00003468
Jeff Laytond00c28d2010-04-24 07:57:44 -04003469 /* search for existing tcon to this server share */
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003470 tcon = cifs_get_tcon(ses, volume_info);
Jeff Laytond00c28d2010-04-24 07:57:44 -04003471 if (IS_ERR(tcon)) {
3472 rc = PTR_ERR(tcon);
3473 tcon = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003474 goto remote_path_check;
Jeff Laytond00c28d2010-04-24 07:57:44 -04003475 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003476
Steve French6848b732011-05-26 18:38:54 +00003477 /* tell server which Unix caps we support */
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04003478 if (cap_unix(tcon->ses)) {
Steve French6848b732011-05-26 18:38:54 +00003479 /* reset of caps checks mount to see if unix extensions
3480 disabled for just this mount */
Al Viro2c6292a2011-06-17 09:05:48 -04003481 reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
Steve French6848b732011-05-26 18:38:54 +00003482 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
3483 (le64_to_cpu(tcon->fsUnixInfo.Capability) &
3484 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) {
3485 rc = -EACCES;
3486 goto mount_fail_check;
3487 }
3488 } else
3489 tcon->unix_ext = 0; /* server does not support them */
3490
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003491 /* do not care if a following call succeed - informational */
3492 if (!tcon->ipc && server->ops->qfs_tcon)
3493 server->ops->qfs_tcon(xid, tcon);
Steve Frenchd82c2df2008-11-15 00:07:26 +00003494
Pavel Shilovsky24985c52012-09-18 16:20:28 -07003495 cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
3496 cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
Jeff Laytonf7910cb2011-05-19 16:22:58 -04003497
Jeff Layton66bfaad2011-10-19 15:30:35 -04003498 /* tune readahead according to rsize */
Jeff Layton8f714652012-05-01 17:41:49 -04003499 cifs_sb->bdi.ra_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
Jeff Layton03ceace2010-12-06 21:07:33 -05003500
Igor Mammedove4cce942009-02-10 14:10:26 +03003501remote_path_check:
3502#ifdef CONFIG_CIFS_DFS_UPCALL
3503 /*
3504 * Perform an unconditional check for whether there are DFS
3505 * referrals for this path without prefix, to provide support
3506 * for DFS referrals from w2k8 servers which don't seem to respond
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003507 * with PATH_NOT_COVERED to requests that include the prefix.
3508 * Chase the referral if found, otherwise continue normally.
Steve Frenchd036f502009-04-03 03:12:08 +00003509 */
Igor Mammedov5c2503a2009-04-21 19:31:05 +04003510 if (referral_walks_count == 0) {
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003511 int refrc = expand_dfs_referral(xid, ses, volume_info, cifs_sb,
3512 false);
Steve Frencheeac8042006-01-13 21:34:58 -08003513 if (!refrc) {
Steve French4523cc32007-04-30 20:13:06 +00003514 referral_walks_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 goto try_mount_again;
3516 }
3517 }
3518#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003519
Steve Frenchf87d39d2011-05-27 03:50:55 +00003520 /* check if a whole path is not remote */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 if (!rc && tcon) {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003522 if (!server->ops->is_path_accessible) {
3523 rc = -ENOSYS;
3524 goto mount_fail_check;
3525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 /* build_path_to_root works only when we have a valid tcon */
Pavel Shilovsky9224dfc2012-05-27 20:39:52 +04003527 full_path = build_path_to_root(volume_info, cifs_sb, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 if (full_path == NULL) {
3529 rc = -ENOMEM;
3530 goto mount_fail_check;
3531 }
Pavel Shilovsky68889f22012-05-25 14:40:22 +04003532 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3533 full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 if (rc != 0 && rc != -EREMOTE) {
3535 kfree(full_path);
3536 goto mount_fail_check;
3537 }
3538 kfree(full_path);
3539 }
3540
3541 /* get referral if needed */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003542 if (rc == -EREMOTE) {
3543#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov5c2503a2009-04-21 19:31:05 +04003544 if (referral_walks_count > MAX_NESTED_LINKS) {
3545 /*
3546 * BB: when we implement proper loop detection,
3547 * we will remove this check. But now we need it
3548 * to prevent an indefinite loop if 'DFS tree' is
3549 * misconfigured (i.e. has loops).
3550 */
3551 rc = -ELOOP;
3552 goto mount_fail_check;
3553 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003554
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003555 rc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, true);
Jeff Layton7b91e262009-07-23 15:22:30 -04003556
Sean Finneydd613942011-04-11 13:19:30 +00003557 if (!rc) {
Igor Mammedov5c2503a2009-04-21 19:31:05 +04003558 referral_walks_count++;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003559 goto try_mount_again;
3560 }
Sean Finneydd613942011-04-11 13:19:30 +00003561 goto mount_fail_check;
Steve Frenchd036f502009-04-03 03:12:08 +00003562#else /* No DFS support, return error on mount */
3563 rc = -EOPNOTSUPP;
3564#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003565 }
3566
Jeff Layton9d002df2010-10-06 19:51:11 -04003567 if (rc)
3568 goto mount_fail_check;
3569
3570 /* now, hang the tcon off of the superblock */
3571 tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
3572 if (tlink == NULL) {
3573 rc = -ENOMEM;
3574 goto mount_fail_check;
3575 }
3576
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003577 tlink->tl_uid = ses->linux_uid;
Jeff Layton9d002df2010-10-06 19:51:11 -04003578 tlink->tl_tcon = tcon;
3579 tlink->tl_time = jiffies;
3580 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
3581 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3582
Jeff Layton413e6612010-10-28 13:33:38 -04003583 cifs_sb->master_tlink = tlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04003584 spin_lock(&cifs_sb->tlink_tree_lock);
3585 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
3586 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton413e6612010-10-28 13:33:38 -04003587
Jeff Laytonda472fc2012-03-23 14:40:53 -04003588 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
Jeff Layton2de970f2010-10-06 19:51:12 -04003589 TLINK_IDLE_EXPIRE);
3590
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003591mount_fail_check:
3592 /* on error free sesinfo and tcon struct if needed */
3593 if (rc) {
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003594 /* If find_unc succeeded then rc == 0 so we can not end */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003595 /* up accidentally freeing someone elses tcon struct */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003596 if (tcon)
3597 cifs_put_tcon(tcon);
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003598 else if (ses)
3599 cifs_put_smb_ses(ses);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003600 else
Pavel Shilovskyaf4281d2012-05-27 20:48:35 +04003601 cifs_put_tcp_session(server);
Al Virodd854462011-06-17 08:24:42 -04003602 bdi_destroy(&cifs_sb->bdi);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003603 }
3604
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003606 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 return rc;
3608}
3609
Jeff Layton8d1bca32011-06-11 21:17:10 -04003610/*
3611 * Issue a TREE_CONNECT request. Note that for IPC$ shares, that the tcon
3612 * pointer may be NULL.
3613 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04003615CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
Steve French96daf2b2011-05-27 04:34:02 +00003616 const char *tree, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 const struct nls_table *nls_codepage)
3618{
3619 struct smb_hdr *smb_buffer;
3620 struct smb_hdr *smb_buffer_response;
3621 TCONX_REQ *pSMB;
3622 TCONX_RSP *pSMBr;
3623 unsigned char *bcc_ptr;
3624 int rc = 0;
Jeff Layton690c5222011-01-20 13:36:51 -05003625 int length;
3626 __u16 bytes_left, count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627
3628 if (ses == NULL)
3629 return -EIO;
3630
3631 smb_buffer = cifs_buf_get();
Steve Frenchca43e3b2009-09-01 17:20:50 +00003632 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 return -ENOMEM;
Steve Frenchca43e3b2009-09-01 17:20:50 +00003634
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 smb_buffer_response = smb_buffer;
3636
3637 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3638 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003639
Pavel Shilovsky88257362012-05-23 14:01:59 +04003640 smb_buffer->Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 smb_buffer->Uid = ses->Suid;
3642 pSMB = (TCONX_REQ *) smb_buffer;
3643 pSMBr = (TCONX_RSP *) smb_buffer_response;
3644
3645 pSMB->AndXCommand = 0xFF;
3646 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 bcc_ptr = &pSMB->Password[0];
Jeff Layton8d1bca32011-06-11 21:17:10 -04003648 if (!tcon || (ses->server->sec_mode & SECMODE_USER)) {
Steve Frencheeac8042006-01-13 21:34:58 -08003649 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003650 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003651 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003652 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003653 } else {
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003654 pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003655 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3656 specified as required (when that support is added to
3657 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003658 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003659 by Samba (not sure whether other servers allow
3660 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003661#ifdef CONFIG_CIFS_WEAK_PW_HASH
Jeff Layton04912d62010-04-24 07:57:45 -04003662 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05003663 (ses->server->secType == LANMAN))
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -05003664 calc_lanman_hash(tcon->password, ses->server->cryptkey,
Steve French96daf2b2011-05-27 04:34:02 +00003665 ses->server->sec_mode &
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003666 SECMODE_PW_ENCRYPT ? true : false,
3667 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003668 else
3669#endif /* CIFS_WEAK_PW_HASH */
Shirish Pargaonkaree2c9252011-01-27 09:58:04 -06003670 rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
Shirish Pargaonkar9ef59922011-10-20 13:21:59 -05003671 bcc_ptr, nls_codepage);
Steve Frencheeac8042006-01-13 21:34:58 -08003672
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003673 bcc_ptr += CIFS_AUTH_RESP_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003674 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003675 /* must align unicode strings */
3676 *bcc_ptr = 0; /* null byte password */
3677 bcc_ptr++;
3678 }
Steve Frencheeac8042006-01-13 21:34:58 -08003679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680
Steve French96daf2b2011-05-27 04:34:02 +00003681 if (ses->server->sec_mode &
Steve Frencha878fb22006-05-30 18:04:19 +00003682 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3684
3685 if (ses->capabilities & CAP_STATUS32) {
3686 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3687 }
3688 if (ses->capabilities & CAP_DFS) {
3689 smb_buffer->Flags2 |= SMBFLG2_DFS;
3690 }
3691 if (ses->capabilities & CAP_UNICODE) {
3692 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3693 length =
Steve Frenchacbbb762012-01-18 22:32:33 -06003694 cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
Steve French50c2f752007-07-13 00:33:32 +00003695 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003696 (/* server len*/ + 256 /* share len */), nls_codepage);
3697 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 bcc_ptr += 2; /* skip trailing null */
3699 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 strcpy(bcc_ptr, tree);
3701 bcc_ptr += strlen(tree) + 1;
3702 }
3703 strcpy(bcc_ptr, "?????");
3704 bcc_ptr += strlen("?????");
3705 bcc_ptr += 1;
3706 count = bcc_ptr - &pSMB->Password[0];
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003707 pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu(
3708 pSMB->hdr.smb_buf_length) + count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 pSMB->ByteCount = cpu_to_le16(count);
3710
Steve French133672e2007-11-13 22:41:37 +00003711 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
Jeff Layton77499812011-01-11 07:24:23 -05003712 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 /* above now done in SendReceive */
3715 if ((rc == 0) && (tcon != NULL)) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003716 bool is_unicode;
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003719 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 tcon->tid = smb_buffer_response->Tid;
3721 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Layton690c5222011-01-20 13:36:51 -05003722 bytes_left = get_bcc(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003723 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003724 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3725 is_unicode = true;
3726 else
3727 is_unicode = false;
3728
Jeff Laytoncc20c032009-04-30 07:16:21 -04003729
Steve French50c2f752007-07-13 00:33:32 +00003730 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003731 if (length == 3) {
3732 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3733 (bcc_ptr[2] == 'C')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003734 cFYI(1, "IPC connection");
Steve French7f8ed422007-09-28 22:28:55 +00003735 tcon->ipc = 1;
3736 }
3737 } else if (length == 2) {
3738 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3739 /* the most common case */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003740 cFYI(1, "disk share connection");
Steve French7f8ed422007-09-28 22:28:55 +00003741 }
3742 }
Steve French50c2f752007-07-13 00:33:32 +00003743 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003744 bytes_left -= (length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003746
3747 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003748 kfree(tcon->nativeFileSystem);
Steve Frenchacbbb762012-01-18 22:32:33 -06003749 tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003750 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003751 nls_codepage);
3752
Joe Perchesb6b38f72010-04-21 03:50:45 +00003753 cFYI(1, "nativeFileSystem=%s", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003754
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003755 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003756 (smb_buffer_response->WordCount == 7))
3757 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003758 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3759 else
3760 tcon->Flags = 0;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003761 cFYI(1, "Tcon flags: 0x%x ", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003763 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 ses->ipc_tid = smb_buffer_response->Tid;
3765 }
3766
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003767 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 return rc;
3769}
3770
Al Viro2a9b9952011-06-17 09:27:16 -04003771void
3772cifs_umount(struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
Jeff Laytonb647c352010-10-28 11:16:44 -04003774 struct rb_root *root = &cifs_sb->tlink_tree;
3775 struct rb_node *node;
3776 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Jeff Layton2de970f2010-10-06 19:51:12 -04003778 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3779
Jeff Laytonb647c352010-10-28 11:16:44 -04003780 spin_lock(&cifs_sb->tlink_tree_lock);
3781 while ((node = rb_first(root))) {
3782 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3783 cifs_get_tlink(tlink);
3784 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3785 rb_erase(node, root);
Steve French50c2f752007-07-13 00:33:32 +00003786
Jeff Laytonb647c352010-10-28 11:16:44 -04003787 spin_unlock(&cifs_sb->tlink_tree_lock);
3788 cifs_put_tlink(tlink);
3789 spin_lock(&cifs_sb->tlink_tree_lock);
3790 }
3791 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003792
Al Virodd854462011-06-17 08:24:42 -04003793 bdi_destroy(&cifs_sb->bdi);
Al Virod757d712011-06-17 09:42:43 -04003794 kfree(cifs_sb->mountdata);
3795 unload_nls(cifs_sb->local_nls);
3796 kfree(cifs_sb);
Steve French50c2f752007-07-13 00:33:32 +00003797}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003799int
3800cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801{
3802 int rc = 0;
Jeff Layton198b5682010-04-24 07:57:48 -04003803 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003805 if (!server->ops->need_neg || !server->ops->negotiate)
3806 return -ENOSYS;
3807
Jeff Layton198b5682010-04-24 07:57:48 -04003808 /* only send once per connect */
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003809 if (!server->ops->need_neg(server))
Jeff Layton198b5682010-04-24 07:57:48 -04003810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811
Pavel Shilovsky45275782012-05-17 17:53:29 +04003812 set_credits(server, 1);
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003813
3814 rc = server->ops->negotiate(xid, ses);
Jeff Layton198b5682010-04-24 07:57:48 -04003815 if (rc == 0) {
3816 spin_lock(&GlobalMid_Lock);
Jeff Layton7fdbaa12011-06-10 16:14:57 -04003817 if (server->tcpStatus == CifsNeedNegotiate)
Jeff Layton198b5682010-04-24 07:57:48 -04003818 server->tcpStatus = CifsGood;
3819 else
3820 rc = -EHOSTDOWN;
3821 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 }
Steve French26b994f2008-08-06 05:11:33 +00003823
Jeff Layton198b5682010-04-24 07:57:48 -04003824 return rc;
3825}
Steve French26b994f2008-08-06 05:11:33 +00003826
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003827int
3828cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
3829 struct nls_table *nls_info)
Jeff Layton198b5682010-04-24 07:57:48 -04003830{
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003831 int rc = -ENOSYS;
Jeff Layton198b5682010-04-24 07:57:48 -04003832 struct TCP_Server_Info *server = ses->server;
3833
3834 ses->flags = 0;
3835 ses->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003836 if (linuxExtEnabled == 0)
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04003837 ses->capabilities &= (~server->vals->cap_unix);
Steve French20418ac2009-04-30 16:13:32 +00003838
Joe Perchesb6b38f72010-04-21 03:50:45 +00003839 cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Steve French96daf2b2011-05-27 04:34:02 +00003840 server->sec_mode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003841
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003842 if (server->ops->sess_setup)
3843 rc = server->ops->sess_setup(xid, ses, nls_info);
3844
Steve French26b994f2008-08-06 05:11:33 +00003845 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003846 cERROR(1, "Send error in SessSetup = %d", rc);
Steve French26b994f2008-08-06 05:11:33 +00003847 } else {
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003848 mutex_lock(&ses->server->srv_mutex);
3849 if (!server->session_estab) {
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003850 server->session_key.response = ses->auth_key.response;
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003851 server->session_key.len = ses->auth_key.len;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003852 server->sequence_number = 0x2;
3853 server->session_estab = true;
3854 ses->auth_key.response = NULL;
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003855 }
3856 mutex_unlock(&server->srv_mutex);
3857
Joe Perchesb6b38f72010-04-21 03:50:45 +00003858 cFYI(1, "CIFS Session Established successfully");
Steve French20418ac2009-04-30 16:13:32 +00003859 spin_lock(&GlobalMid_Lock);
Jeff Layton198b5682010-04-24 07:57:48 -04003860 ses->status = CifsGood;
3861 ses->need_reconnect = false;
Steve French20418ac2009-04-30 16:13:32 +00003862 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003863 }
3864
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003865 kfree(ses->auth_key.response);
3866 ses->auth_key.response = NULL;
3867 ses->auth_key.len = 0;
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05003868 kfree(ses->ntlmssp);
3869 ses->ntlmssp = NULL;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 return rc;
3872}
3873
Jeff Layton8a8798a2012-01-17 16:09:15 -05003874static int
3875cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
3876{
3877 switch (ses->server->secType) {
3878 case Kerberos:
3879 vol->secFlg = CIFSSEC_MUST_KRB5;
3880 return 0;
3881 case NTLMv2:
3882 vol->secFlg = CIFSSEC_MUST_NTLMV2;
3883 break;
3884 case NTLM:
3885 vol->secFlg = CIFSSEC_MUST_NTLM;
3886 break;
3887 case RawNTLMSSP:
3888 vol->secFlg = CIFSSEC_MUST_NTLMSSP;
3889 break;
3890 case LANMAN:
3891 vol->secFlg = CIFSSEC_MUST_LANMAN;
3892 break;
3893 }
3894
3895 return cifs_set_cifscreds(vol, ses);
3896}
3897
Steve French96daf2b2011-05-27 04:34:02 +00003898static struct cifs_tcon *
Jeff Layton9d002df2010-10-06 19:51:11 -04003899cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
3900{
Jeff Layton8a8798a2012-01-17 16:09:15 -05003901 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00003902 struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
3903 struct cifs_ses *ses;
3904 struct cifs_tcon *tcon = NULL;
Jeff Layton9d002df2010-10-06 19:51:11 -04003905 struct smb_vol *vol_info;
Jeff Layton9d002df2010-10-06 19:51:11 -04003906
3907 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
Dan Carpenter803ab972012-01-24 11:39:22 +03003908 if (vol_info == NULL)
3909 return ERR_PTR(-ENOMEM);
Jeff Layton9d002df2010-10-06 19:51:11 -04003910
Jeff Layton9d002df2010-10-06 19:51:11 -04003911 vol_info->local_nls = cifs_sb->local_nls;
3912 vol_info->linux_uid = fsuid;
3913 vol_info->cred_uid = fsuid;
3914 vol_info->UNC = master_tcon->treeName;
3915 vol_info->retry = master_tcon->retry;
3916 vol_info->nocase = master_tcon->nocase;
3917 vol_info->local_lease = master_tcon->local_lease;
3918 vol_info->no_linux_ext = !master_tcon->unix_ext;
3919
Jeff Layton8a8798a2012-01-17 16:09:15 -05003920 rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
3921 if (rc) {
3922 tcon = ERR_PTR(rc);
3923 goto out;
3924 }
Jeff Layton9d002df2010-10-06 19:51:11 -04003925
3926 /* get a reference for the same TCP session */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303927 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003928 ++master_tcon->ses->server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303929 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003930
3931 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
3932 if (IS_ERR(ses)) {
Steve French96daf2b2011-05-27 04:34:02 +00003933 tcon = (struct cifs_tcon *)ses;
Jeff Layton9d002df2010-10-06 19:51:11 -04003934 cifs_put_tcp_session(master_tcon->ses->server);
3935 goto out;
3936 }
3937
3938 tcon = cifs_get_tcon(ses, vol_info);
3939 if (IS_ERR(tcon)) {
3940 cifs_put_smb_ses(ses);
3941 goto out;
3942 }
3943
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04003944 if (cap_unix(ses))
Jeff Layton9d002df2010-10-06 19:51:11 -04003945 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
3946out:
Jeff Layton8a8798a2012-01-17 16:09:15 -05003947 kfree(vol_info->username);
3948 kfree(vol_info->password);
Jeff Layton9d002df2010-10-06 19:51:11 -04003949 kfree(vol_info);
3950
3951 return tcon;
3952}
3953
Steve French96daf2b2011-05-27 04:34:02 +00003954struct cifs_tcon *
Jeff Layton9d002df2010-10-06 19:51:11 -04003955cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3956{
3957 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3958}
3959
3960static int
3961cifs_sb_tcon_pending_wait(void *unused)
3962{
3963 schedule();
3964 return signal_pending(current) ? -ERESTARTSYS : 0;
3965}
3966
Jeff Laytonb647c352010-10-28 11:16:44 -04003967/* find and return a tlink with given uid */
3968static struct tcon_link *
3969tlink_rb_search(struct rb_root *root, uid_t uid)
3970{
3971 struct rb_node *node = root->rb_node;
3972 struct tcon_link *tlink;
3973
3974 while (node) {
3975 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3976
3977 if (tlink->tl_uid > uid)
3978 node = node->rb_left;
3979 else if (tlink->tl_uid < uid)
3980 node = node->rb_right;
3981 else
3982 return tlink;
3983 }
3984 return NULL;
3985}
3986
3987/* insert a tcon_link into the tree */
3988static void
3989tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
3990{
3991 struct rb_node **new = &(root->rb_node), *parent = NULL;
3992 struct tcon_link *tlink;
3993
3994 while (*new) {
3995 tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
3996 parent = *new;
3997
3998 if (tlink->tl_uid > new_tlink->tl_uid)
3999 new = &((*new)->rb_left);
4000 else
4001 new = &((*new)->rb_right);
4002 }
4003
4004 rb_link_node(&new_tlink->tl_rbnode, parent, new);
4005 rb_insert_color(&new_tlink->tl_rbnode, root);
4006}
4007
Jeff Layton9d002df2010-10-06 19:51:11 -04004008/*
4009 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
4010 * current task.
4011 *
4012 * If the superblock doesn't refer to a multiuser mount, then just return
4013 * the master tcon for the mount.
4014 *
Suresh Jayaraman6ef933a2010-11-03 10:53:49 +05304015 * First, search the rbtree for an existing tcon for this fsuid. If one
Jeff Layton9d002df2010-10-06 19:51:11 -04004016 * exists, then check to see if it's pending construction. If it is then wait
4017 * for construction to complete. Once it's no longer pending, check to see if
4018 * it failed and either return an error or retry construction, depending on
4019 * the timeout.
4020 *
4021 * If one doesn't exist then insert a new tcon_link struct into the tree and
4022 * try to construct a new one.
4023 */
4024struct tcon_link *
4025cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
4026{
4027 int ret;
Jeff Laytonb647c352010-10-28 11:16:44 -04004028 uid_t fsuid = current_fsuid();
Jeff Layton9d002df2010-10-06 19:51:11 -04004029 struct tcon_link *tlink, *newtlink;
4030
4031 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
4032 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
4033
4034 spin_lock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04004035 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04004036 if (tlink)
4037 cifs_get_tlink(tlink);
4038 spin_unlock(&cifs_sb->tlink_tree_lock);
4039
4040 if (tlink == NULL) {
4041 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
4042 if (newtlink == NULL)
4043 return ERR_PTR(-ENOMEM);
Jeff Laytonb647c352010-10-28 11:16:44 -04004044 newtlink->tl_uid = fsuid;
Jeff Layton9d002df2010-10-06 19:51:11 -04004045 newtlink->tl_tcon = ERR_PTR(-EACCES);
4046 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
4047 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
4048 cifs_get_tlink(newtlink);
4049
Jeff Layton9d002df2010-10-06 19:51:11 -04004050 spin_lock(&cifs_sb->tlink_tree_lock);
4051 /* was one inserted after previous search? */
Jeff Laytonb647c352010-10-28 11:16:44 -04004052 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04004053 if (tlink) {
4054 cifs_get_tlink(tlink);
4055 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04004056 kfree(newtlink);
4057 goto wait_for_construction;
4058 }
Jeff Layton9d002df2010-10-06 19:51:11 -04004059 tlink = newtlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04004060 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
4061 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04004062 } else {
4063wait_for_construction:
4064 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
4065 cifs_sb_tcon_pending_wait,
4066 TASK_INTERRUPTIBLE);
4067 if (ret) {
4068 cifs_put_tlink(tlink);
4069 return ERR_PTR(ret);
4070 }
4071
4072 /* if it's good, return it */
4073 if (!IS_ERR(tlink->tl_tcon))
4074 return tlink;
4075
4076 /* return error if we tried this already recently */
4077 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
4078 cifs_put_tlink(tlink);
4079 return ERR_PTR(-EACCES);
4080 }
4081
4082 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
4083 goto wait_for_construction;
4084 }
4085
4086 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
4087 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
4088 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
4089
4090 if (IS_ERR(tlink->tl_tcon)) {
4091 cifs_put_tlink(tlink);
4092 return ERR_PTR(-EACCES);
4093 }
4094
4095 return tlink;
4096}
Jeff Layton2de970f2010-10-06 19:51:12 -04004097
4098/*
4099 * periodic workqueue job that scans tcon_tree for a superblock and closes
4100 * out tcons.
4101 */
4102static void
4103cifs_prune_tlinks(struct work_struct *work)
4104{
4105 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
4106 prune_tlinks.work);
Jeff Laytonb647c352010-10-28 11:16:44 -04004107 struct rb_root *root = &cifs_sb->tlink_tree;
4108 struct rb_node *node = rb_first(root);
4109 struct rb_node *tmp;
4110 struct tcon_link *tlink;
Jeff Layton2de970f2010-10-06 19:51:12 -04004111
Jeff Laytonb647c352010-10-28 11:16:44 -04004112 /*
4113 * Because we drop the spinlock in the loop in order to put the tlink
4114 * it's not guarded against removal of links from the tree. The only
4115 * places that remove entries from the tree are this function and
4116 * umounts. Because this function is non-reentrant and is canceled
4117 * before umount can proceed, this is safe.
4118 */
4119 spin_lock(&cifs_sb->tlink_tree_lock);
4120 node = rb_first(root);
4121 while (node != NULL) {
4122 tmp = node;
4123 node = rb_next(tmp);
4124 tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
4125
4126 if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
4127 atomic_read(&tlink->tl_count) != 0 ||
4128 time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
4129 continue;
4130
4131 cifs_get_tlink(tlink);
4132 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4133 rb_erase(tmp, root);
4134
Jeff Layton2de970f2010-10-06 19:51:12 -04004135 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04004136 cifs_put_tlink(tlink);
4137 spin_lock(&cifs_sb->tlink_tree_lock);
4138 }
4139 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton2de970f2010-10-06 19:51:12 -04004140
Jeff Laytonda472fc2012-03-23 14:40:53 -04004141 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
Jeff Layton2de970f2010-10-06 19:51:12 -04004142 TLINK_IDLE_EXPIRE);
4143}