blob: c8ef24bac94fc7015df7358f52a2478ec8355f74 [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>
Eric Biggersdc920272020-03-08 22:58:20 -070024#include <linux/sched/mm.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010025#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/list.h>
27#include <linux/wait.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/pagemap.h>
30#include <linux/ctype.h>
31#include <linux/utsname.h>
32#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070033#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070034#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000035#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070036#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080037#include <linux/freezer.h>
Igor Mammedov5c2503a2009-04-21 19:31:05 +040038#include <linux/namei.h>
Andrew Lunnc6e970a2017-03-28 23:45:06 +020039#include <linux/uuid.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080040#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <asm/processor.h>
Jeff Layton50b64e32009-06-02 06:55:20 -040042#include <linux/inet.h>
Paul Gortmaker143cb492011-07-01 14:23:34 -040043#include <linux/module.h>
Jeff Layton8a8798a2012-01-17 16:09:15 -050044#include <keys/user-type.h>
Steve French0e2beda2009-01-30 21:24:41 +000045#include <net/ipv6.h>
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040046#include <linux/parser.h>
Christoph Hellwig2f8b5442016-11-01 07:40:13 -060047#include <linux/bvec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include "cifspdu.h"
49#include "cifsglob.h"
50#include "cifsproto.h"
51#include "cifs_unicode.h"
52#include "cifs_debug.h"
53#include "cifs_fs_sb.h"
54#include "ntlmssp.h"
55#include "nterr.h"
56#include "rfc1002pdu.h"
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053057#include "fscache.h"
Pavel Shilovsky53e0e112016-11-04 11:50:31 -070058#include "smb2proto.h"
Long Li2f894642017-11-22 17:38:34 -070059#include "smbdirect.h"
Paulo Alcantara1c780222018-11-14 16:24:03 -020060#include "dns_resolve.h"
61#ifdef CONFIG_CIFS_DFS_UPCALL
62#include "dfs_cache.h"
63#endif
Ronnie Sahlberg5c6e5aa2020-10-21 10:37:11 +100064#include "fs_context.h"
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +010065#ifdef CONFIG_CIFS_SWN_UPCALL
66#include "cifs_swn.h"
67#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Linus Torvalds1da177e2005-04-16 15:20:36 -070069extern mempool_t *cifs_req_poolp;
Steve Frenchf92a7202018-05-24 04:11:07 -050070extern bool disable_legacy_dialects;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jeff Layton2de970f2010-10-06 19:51:12 -040072/* FIXME: should these be tunable? */
Jeff Layton9d002df2010-10-06 19:51:11 -040073#define TLINK_ERROR_EXPIRE (1 * HZ)
Jeff Layton2de970f2010-10-06 19:51:12 -040074#define TLINK_IDLE_EXPIRE (600 * HZ)
Jeff Layton9d002df2010-10-06 19:51:11 -040075
Rohith Surabattula8e670f72020-09-18 05:37:28 +000076/* Drop the connection to not overload the server */
77#define NUM_STATUS_IO_TIMEOUT 5
78
Pavel Shilovskya9f1b852010-12-13 19:08:35 +030079static int ip_connect(struct TCP_Server_Info *server);
80static int generic_ip_connect(struct TCP_Server_Info *server);
Jeff Laytonb647c352010-10-28 11:16:44 -040081static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
Jeff Layton2de970f2010-10-06 19:51:12 -040082static void cifs_prune_tlinks(struct work_struct *work);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -020083
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020084/*
85 * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
86 * get their ip addresses changed at some point.
87 *
88 * This should be called with server->srv_mutex held.
89 */
90#ifdef CONFIG_CIFS_DFS_UPCALL
Samuel Cabrero7d6535b2020-11-30 19:02:55 +010091static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020092{
93 int rc;
94 int len;
95 char *unc, *ipaddr = NULL;
96
97 if (!server->hostname)
98 return -EINVAL;
99
100 len = strlen(server->hostname) + 3;
101
102 unc = kmalloc(len, GFP_KERNEL);
103 if (!unc) {
104 cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
105 return -ENOMEM;
106 }
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +1000107 scnprintf(unc, len, "\\\\%s", server->hostname);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200108
109 rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
110 kfree(unc);
111
112 if (rc < 0) {
113 cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
114 __func__, server->hostname, rc);
115 return rc;
116 }
117
Ronnie Sahlbergfada37f2020-04-21 12:37:39 +1000118 spin_lock(&cifs_tcp_ses_lock);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200119 rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
120 strlen(ipaddr));
Ronnie Sahlbergfada37f2020-04-21 12:37:39 +1000121 spin_unlock(&cifs_tcp_ses_lock);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200122 kfree(ipaddr);
123
124 return !rc ? -1 : 0;
125}
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200126
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200127/* These functions must be called with server->srv_mutex held */
Paulo Alcantara7d397a02020-07-21 09:36:40 -0300128static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,
129 struct cifs_sb_info *cifs_sb,
130 struct dfs_cache_tgt_list *tgt_list,
131 struct dfs_cache_tgt_iterator **tgt_it)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200132{
133 const char *name;
Samuel Cabrero7d6535b2020-11-30 19:02:55 +0100134 int rc;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200135
Paulo Alcantara7d397a02020-07-21 09:36:40 -0300136 if (!cifs_sb || !cifs_sb->origin_fullpath)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200137 return;
138
139 if (!*tgt_it) {
140 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
141 } else {
142 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
143 if (!*tgt_it)
144 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
145 }
146
147 cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath);
148
149 name = dfs_cache_get_tgt_name(*tgt_it);
150
151 kfree(server->hostname);
152
153 server->hostname = extract_hostname(name);
Dan Carpenter84288172019-01-05 15:25:29 +0300154 if (IS_ERR(server->hostname)) {
155 cifs_dbg(FYI,
156 "%s: failed to extract hostname from target: %ld\n",
157 __func__, PTR_ERR(server->hostname));
Samuel Cabrero0bf1baf2020-12-18 10:29:49 +0100158 return;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200159 }
Samuel Cabrero7d6535b2020-11-30 19:02:55 +0100160
161 rc = reconn_set_ipaddr_from_hostname(server);
162 if (rc) {
163 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
164 __func__, rc);
165 }
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200166}
167
168static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb,
Paulo Alcantarabaf3f082020-05-19 15:38:29 -0300169 struct dfs_cache_tgt_list *tl)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200170{
171 if (!cifs_sb->origin_fullpath)
172 return -EOPNOTSUPP;
173 return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl);
174}
175#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Jeff Laytond5c56052008-12-01 18:42:33 -0500177/*
178 * cifs tcp session reconnection
179 *
180 * mark tcp session as reconnecting so temporarily locked
181 * mark all smb sessions as reconnecting for tcp session
182 * reconnect tcp session
183 * wake up waiters on reconnection? - (not needed currently)
184 */
Pavel Shilovsky28ea5292012-05-23 16:18:00 +0400185int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186cifs_reconnect(struct TCP_Server_Info *server)
187{
188 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500189 struct list_head *tmp, *tmp2;
Steve French96daf2b2011-05-27 04:34:02 +0000190 struct cifs_ses *ses;
191 struct cifs_tcon *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000192 struct mid_q_entry *mid_entry;
Jeff Layton3c1105d2011-05-22 07:09:13 -0400193 struct list_head retry_list;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200194#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300195 struct super_block *sb = NULL;
Paulo Alcantara23324402018-11-20 14:37:18 -0200196 struct cifs_sb_info *cifs_sb = NULL;
197 struct dfs_cache_tgt_list tgt_list = {0};
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200198 struct dfs_cache_tgt_iterator *tgt_it = NULL;
199#endif
Steve French50c2f752007-07-13 00:33:32 +0000200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 spin_lock(&GlobalMid_Lock);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200202 server->nr_targets = 1;
203#ifdef CONFIG_CIFS_DFS_UPCALL
Ronnie Sahlberg61cabc72019-06-14 13:02:29 +1000204 spin_unlock(&GlobalMid_Lock);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300205 sb = cifs_get_tcp_super(server);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300206 if (IS_ERR(sb)) {
207 rc = PTR_ERR(sb);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200208 cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
209 __func__, rc);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300210 sb = NULL;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200211 } else {
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300212 cifs_sb = CIFS_SB(sb);
Paulo Alcantarabaf3f082020-05-19 15:38:29 -0300213 rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list);
Paulo Alcantaraa5293032020-07-21 09:36:41 -0300214 if (rc) {
215 cifs_sb = NULL;
216 if (rc != -EOPNOTSUPP) {
217 cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
218 __func__);
219 }
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200220 } else {
221 server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
222 }
223 }
224 cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__,
225 server->nr_targets);
Ronnie Sahlberg61cabc72019-06-14 13:02:29 +1000226 spin_lock(&GlobalMid_Lock);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200227#endif
Jeff Layton469ee612008-10-16 18:46:39 +0000228 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000229 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 next time through the loop */
231 spin_unlock(&GlobalMid_Lock);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300232#ifdef CONFIG_CIFS_DFS_UPCALL
233 dfs_cache_free_tgts(&tgt_list);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300234 cifs_put_tcp_super(sb);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300235#endif
Stefan Metzmachere2e87512020-02-24 14:31:02 -0600236 wake_up(&server->response_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return rc;
238 } else
239 server->tcpStatus = CifsNeedReconnect;
240 spin_unlock(&GlobalMid_Lock);
241 server->maxBuf = 0;
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400242 server->max_read = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Steve French6e4d3bb2018-09-22 11:25:04 -0500244 cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
Steve Frenchbf1fdeb2018-07-30 19:23:09 -0500245 trace_smb3_reconnect(server->CurrentMid, server->hostname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 /* before reconnecting the tcp session, mark the smb session (uid)
248 and the tid bad so they are not used until reconnected */
Joe Perchesf96637b2013-05-04 22:12:25 -0500249 cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
250 __func__);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530251 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500252 list_for_each(tmp, &server->smb_ses_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000253 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
Jeff Layton14fbf502008-11-14 13:53:46 -0500254 ses->need_reconnect = true;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500255 list_for_each(tmp2, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000256 tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500257 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Aurelien Aptelb327a712018-01-24 13:46:10 +0100259 if (ses->tcon_ipc)
260 ses->tcon_ipc->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530262 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 /* do not want to be sending data on a socket we are freeing */
Joe Perchesf96637b2013-05-04 22:12:25 -0500265 cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
Jeff Layton72ca5452008-12-01 07:09:36 -0500266 mutex_lock(&server->srv_mutex);
Long Li1d2a4f52019-05-13 21:01:28 -0700267 if (server->ssocket) {
268 cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
269 server->ssocket->state, server->ssocket->flags);
270 kernel_sock_shutdown(server->ssocket, SHUT_WR);
271 cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
272 server->ssocket->state, server->ssocket->flags);
273 sock_release(server->ssocket);
274 server->ssocket = NULL;
275 }
276 server->sequence_number = 0;
277 server->session_estab = false;
278 kfree(server->session_key.response);
279 server->session_key.response = NULL;
280 server->session_key.len = 0;
281 server->lstrp = jiffies;
Long Li214bab42019-04-05 21:36:35 +0000282
283 /* mark submitted MIDs for retry and issue callback */
284 INIT_LIST_HEAD(&retry_list);
285 cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
286 spin_lock(&GlobalMid_Lock);
287 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
288 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700289 kref_get(&mid_entry->refcount);
Long Li214bab42019-04-05 21:36:35 +0000290 if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
291 mid_entry->mid_state = MID_RETRY_NEEDED;
292 list_move(&mid_entry->qhead, &retry_list);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700293 mid_entry->mid_flags |= MID_DELETED;
Long Li214bab42019-04-05 21:36:35 +0000294 }
295 spin_unlock(&GlobalMid_Lock);
Long Li1d2a4f52019-05-13 21:01:28 -0700296 mutex_unlock(&server->srv_mutex);
Long Li214bab42019-04-05 21:36:35 +0000297
298 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
299 list_for_each_safe(tmp, tmp2, &retry_list) {
300 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
301 list_del_init(&mid_entry->qhead);
302 mid_entry->callback(mid_entry);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700303 cifs_mid_q_entry_release(mid_entry);
Long Li214bab42019-04-05 21:36:35 +0000304 }
305
Long Li1d2a4f52019-05-13 21:01:28 -0700306 if (cifs_rdma_enabled(server)) {
307 mutex_lock(&server->srv_mutex);
Long Li050b8c32019-04-04 11:35:42 -0500308 smbd_destroy(server);
Long Li1d2a4f52019-05-13 21:01:28 -0700309 mutex_unlock(&server->srv_mutex);
310 }
Jeff Layton3c1105d2011-05-22 07:09:13 -0400311
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400312 do {
Steve French6c3d8902006-07-31 22:46:20 +0000313 try_to_freeze();
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300314
Jeff Layton73e216a2013-09-05 08:38:10 -0400315 mutex_lock(&server->srv_mutex);
Samuel Cabrero121d9472020-11-30 19:02:56 +0100316
317#ifdef CONFIG_CIFS_SWN_UPCALL
318 if (server->use_swn_dstaddr) {
319 server->dstaddr = server->swn_dstaddr;
320 } else {
321#endif
322
Paulo Alcantaraaaa3aef2020-05-19 15:38:27 -0300323#ifdef CONFIG_CIFS_DFS_UPCALL
Samuel Cabrero121d9472020-11-30 19:02:56 +0100324 /*
325 * Set up next DFS target server (if any) for reconnect. If DFS
326 * feature is disabled, then we will retry last server we
327 * connected to before.
328 */
329 reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it);
330#endif
331
332#ifdef CONFIG_CIFS_SWN_UPCALL
333 }
Paulo Alcantaraaaa3aef2020-05-19 15:38:27 -0300334#endif
Paulo Alcantaraaaa3aef2020-05-19 15:38:27 -0300335
Long Li781a8052017-11-22 17:38:36 -0700336 if (cifs_rdma_enabled(server))
337 rc = smbd_reconnect(server);
338 else
339 rc = generic_ip_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000340 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500341 cifs_dbg(FYI, "reconnect error %d\n", rc);
Federico Sauter4afe2602015-03-17 17:45:28 +0100342 mutex_unlock(&server->srv_mutex);
Steve French0cb766a2005-04-28 22:41:11 -0700343 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 } else {
345 atomic_inc(&tcpSesReconnectCount);
Pavel Shilovsky335b7b62019-01-16 11:12:41 -0800346 set_credits(server, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000348 if (server->tcpStatus != CifsExiting)
Steve Frenchfd88ce92011-04-12 01:01:14 +0000349 server->tcpStatus = CifsNeedNegotiate;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000350 spin_unlock(&GlobalMid_Lock);
Samuel Cabrero121d9472020-11-30 19:02:56 +0100351#ifdef CONFIG_CIFS_SWN_UPCALL
352 server->use_swn_dstaddr = false;
353#endif
Federico Sauter4afe2602015-03-17 17:45:28 +0100354 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 }
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400356 } while (server->tcpStatus == CifsNeedReconnect);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500357
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200358#ifdef CONFIG_CIFS_DFS_UPCALL
359 if (tgt_it) {
360 rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
361 tgt_it);
362 if (rc) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000363 cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200364 __func__, rc);
365 }
366 rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
367 if (rc) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000368 cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200369 __func__, rc);
370 }
Paulo Alcantara23324402018-11-20 14:37:18 -0200371 dfs_cache_free_tgts(&tgt_list);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300372
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200373 }
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300374
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300375 cifs_put_tcp_super(sb);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200376#endif
Sachin Prabhub8c60012016-10-20 19:52:24 -0400377 if (server->tcpStatus == CifsNeedNegotiate)
378 mod_delayed_work(cifsiod_wq, &server->echo, 0);
379
Stefan Metzmachere2e87512020-02-24 14:31:02 -0600380 wake_up(&server->response_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 return rc;
382}
383
Jeff Laytonc74093b2011-01-11 07:24:23 -0500384static void
385cifs_echo_request(struct work_struct *work)
386{
387 int rc;
388 struct TCP_Server_Info *server = container_of(work,
389 struct TCP_Server_Info, echo.work);
Sachin Prabhub8c60012016-10-20 19:52:24 -0400390 unsigned long echo_interval;
Jeff Laytonc74093b2011-01-11 07:24:23 -0500391
Jeff Layton247ec9b2011-02-04 17:09:50 -0500392 /*
Sachin Prabhub8c60012016-10-20 19:52:24 -0400393 * If we need to renegotiate, set echo interval to zero to
394 * immediately call echo service where we can renegotiate.
395 */
396 if (server->tcpStatus == CifsNeedNegotiate)
397 echo_interval = 0;
398 else
399 echo_interval = server->echo_interval;
400
401 /*
402 * We cannot send an echo if it is disabled.
403 * Also, no need to ping if we got a response recently.
Jeff Layton247ec9b2011-02-04 17:09:50 -0500404 */
Steve French4fcd1812016-06-22 20:12:05 -0500405
406 if (server->tcpStatus == CifsNeedReconnect ||
Sachin Prabhub8c60012016-10-20 19:52:24 -0400407 server->tcpStatus == CifsExiting ||
408 server->tcpStatus == CifsNew ||
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400409 (server->ops->can_echo && !server->ops->can_echo(server)) ||
Steve Frenchadfeb3e2015-12-18 12:31:36 -0600410 time_before(jiffies, server->lstrp + echo_interval - HZ))
Jeff Laytonc74093b2011-01-11 07:24:23 -0500411 goto requeue_echo;
412
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400413 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
Jeff Laytonc74093b2011-01-11 07:24:23 -0500414 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500415 cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
416 server->hostname);
Jeff Laytonc74093b2011-01-11 07:24:23 -0500417
Samuel Cabrero21077c62020-11-30 19:02:54 +0100418#ifdef CONFIG_CIFS_SWN_UPCALL
419 /* Check witness registrations */
420 cifs_swn_check();
421#endif
422
Jeff Laytonc74093b2011-01-11 07:24:23 -0500423requeue_echo:
Sachin Prabhub8c60012016-10-20 19:52:24 -0400424 queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
Jeff Laytonc74093b2011-01-11 07:24:23 -0500425}
426
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400427static bool
Jeff Layton2a37ef92011-10-19 15:29:23 -0400428allocate_buffers(struct TCP_Server_Info *server)
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400429{
Jeff Layton2a37ef92011-10-19 15:29:23 -0400430 if (!server->bigbuf) {
431 server->bigbuf = (char *)cifs_buf_get();
432 if (!server->bigbuf) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000433 cifs_server_dbg(VFS, "No memory for large SMB response\n");
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400434 msleep(3000);
435 /* retry will check if exiting */
436 return false;
437 }
Jeff Layton2a37ef92011-10-19 15:29:23 -0400438 } else if (server->large_buf) {
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400439 /* we are reusing a dirty large buf, clear its start */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400440 memset(server->bigbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400441 }
442
Jeff Layton2a37ef92011-10-19 15:29:23 -0400443 if (!server->smallbuf) {
444 server->smallbuf = (char *)cifs_small_buf_get();
445 if (!server->smallbuf) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000446 cifs_server_dbg(VFS, "No memory for SMB response\n");
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400447 msleep(1000);
448 /* retry will check if exiting */
449 return false;
450 }
451 /* beginning of smb buffer is cleared in our buf_get */
452 } else {
453 /* if existing small buf clear beginning */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400454 memset(server->smallbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400455 }
456
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400457 return true;
458}
459
Jeff Laytonba749e62011-10-11 06:41:32 -0400460static bool
461server_unresponsive(struct TCP_Server_Info *server)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400462{
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300463 /*
Ronnie Sahlbergf2caf902019-07-06 06:52:46 +1000464 * We need to wait 3 echo intervals to make sure we handle such
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300465 * situations right:
466 * 1s client sends a normal SMB request
Ronnie Sahlbergbecc2ba2019-07-24 11:43:49 +1000467 * 2s client gets a response
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300468 * 30s echo workqueue job pops, and decides we got a response recently
469 * and don't need to send another
470 * ...
471 * 65s kernel_recvmsg times out, and we see that we haven't gotten
472 * a response in >60s.
473 */
Samuel Cabrero76e75272017-07-11 12:44:39 +0200474 if ((server->tcpStatus == CifsGood ||
475 server->tcpStatus == CifsNeedNegotiate) &&
Ronnie Sahlbergf2caf902019-07-06 06:52:46 +1000476 time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000477 cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
478 (3 * server->echo_interval) / HZ);
Jeff Laytonba749e62011-10-11 06:41:32 -0400479 cifs_reconnect(server);
Jeff Laytonba749e62011-10-11 06:41:32 -0400480 return true;
481 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400482
Jeff Laytonba749e62011-10-11 06:41:32 -0400483 return false;
484}
485
Pavel Shilovskyef68e832019-01-18 17:25:36 -0800486static inline bool
487zero_credits(struct TCP_Server_Info *server)
488{
489 int val;
490
491 spin_lock(&server->req_lock);
492 val = server->credits + server->echo_credits + server->oplock_credits;
493 if (server->in_flight == 0 && val == 0) {
494 spin_unlock(&server->req_lock);
495 return true;
496 }
497 spin_unlock(&server->req_lock);
498 return false;
499}
500
Al Viro71335662016-01-09 19:54:50 -0500501static int
502cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400503{
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400504 int length = 0;
505 int total_read;
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400506
Al Viro71335662016-01-09 19:54:50 -0500507 smb_msg->msg_control = NULL;
508 smb_msg->msg_controllen = 0;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400509
Al Viro71335662016-01-09 19:54:50 -0500510 for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
Jeff Layton95edcff2011-12-01 20:22:41 -0500511 try_to_freeze();
512
Pavel Shilovskyef68e832019-01-18 17:25:36 -0800513 /* reconnect if no credits and no requests in flight */
514 if (zero_credits(server)) {
515 cifs_reconnect(server);
516 return -ECONNABORTED;
517 }
518
Al Viro71335662016-01-09 19:54:50 -0500519 if (server_unresponsive(server))
520 return -ECONNABORTED;
Long Li2fef1372017-11-22 17:38:41 -0700521 if (cifs_rdma_enabled(server) && server->smbd_conn)
522 length = smbd_recv(server->smbd_conn, smb_msg);
523 else
524 length = sock_recvmsg(server->ssocket, smb_msg, 0);
Al Viro71335662016-01-09 19:54:50 -0500525
526 if (server->tcpStatus == CifsExiting)
527 return -ESHUTDOWN;
528
529 if (server->tcpStatus == CifsNeedReconnect) {
530 cifs_reconnect(server);
531 return -ECONNABORTED;
Jeff Laytonba749e62011-10-11 06:41:32 -0400532 }
533
Al Viro71335662016-01-09 19:54:50 -0500534 if (length == -ERESTARTSYS ||
535 length == -EAGAIN ||
536 length == -EINTR) {
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400537 /*
538 * Minimum sleep to prevent looping, allowing socket
539 * to clear and app threads to set tcpStatus
540 * CifsNeedReconnect if server hung.
541 */
542 usleep_range(1000, 2000);
543 length = 0;
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400544 continue;
Al Viro71335662016-01-09 19:54:50 -0500545 }
546
547 if (length <= 0) {
Al Viro09aab882015-11-13 03:00:17 -0500548 cifs_dbg(FYI, "Received no data or error: %d\n", length);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400549 cifs_reconnect(server);
Al Viro71335662016-01-09 19:54:50 -0500550 return -ECONNABORTED;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400551 }
552 }
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400553 return total_read;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400554}
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400555
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400556int
557cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
558 unsigned int to_read)
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400559{
Al Viro71335662016-01-09 19:54:50 -0500560 struct msghdr smb_msg;
561 struct kvec iov = {.iov_base = buf, .iov_len = to_read};
David Howellsaa563d72018-10-20 00:57:56 +0100562 iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400563
Al Viro71335662016-01-09 19:54:50 -0500564 return cifs_readv_from_socket(server, &smb_msg);
565}
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400566
Al Viro71335662016-01-09 19:54:50 -0500567int
568cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
Long Li1dbe3462018-05-30 12:47:55 -0700569 unsigned int page_offset, unsigned int to_read)
Al Viro71335662016-01-09 19:54:50 -0500570{
571 struct msghdr smb_msg;
Long Li1dbe3462018-05-30 12:47:55 -0700572 struct bio_vec bv = {
573 .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
David Howellsaa563d72018-10-20 00:57:56 +0100574 iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
Al Viro71335662016-01-09 19:54:50 -0500575 return cifs_readv_from_socket(server, &smb_msg);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400576}
577
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400578static bool
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400579is_smb_response(struct TCP_Server_Info *server, unsigned char type)
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400580{
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400581 /*
582 * The first byte big endian of the length field,
583 * is actually not part of the length but the type
584 * with the most common, zero, as regular data.
585 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400586 switch (type) {
587 case RFC1002_SESSION_MESSAGE:
588 /* Regular SMB response */
589 return true;
590 case RFC1002_SESSION_KEEP_ALIVE:
Joe Perchesf96637b2013-05-04 22:12:25 -0500591 cifs_dbg(FYI, "RFC 1002 session keep alive\n");
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400592 break;
593 case RFC1002_POSITIVE_SESSION_RESPONSE:
Joe Perchesf96637b2013-05-04 22:12:25 -0500594 cifs_dbg(FYI, "RFC 1002 positive session response\n");
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400595 break;
596 case RFC1002_NEGATIVE_SESSION_RESPONSE:
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400597 /*
598 * We get this from Windows 98 instead of an error on
599 * SMB negprot response.
600 */
Joe Perchesf96637b2013-05-04 22:12:25 -0500601 cifs_dbg(FYI, "RFC 1002 negative session response\n");
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400602 /* give server a second to clean up */
603 msleep(1000);
604 /*
605 * Always try 445 first on reconnect since we get NACK
606 * on some if we ever connected to port 139 (the NACK
607 * is since we do not begin with RFC1001 session
608 * initialize frame).
609 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400610 cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400611 cifs_reconnect(server);
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400612 break;
613 default:
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000614 cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400615 cifs_reconnect(server);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400616 }
617
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400618 return false;
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400619}
620
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400621void
622dequeue_mid(struct mid_q_entry *mid, bool malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400623{
624#ifdef CONFIG_CIFS_STATS2
625 mid->when_received = jiffies;
626#endif
627 spin_lock(&GlobalMid_Lock);
628 if (!malformed)
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400629 mid->mid_state = MID_RESPONSE_RECEIVED;
Jeff Laytonea1f4502011-10-19 15:29:05 -0400630 else
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400631 mid->mid_state = MID_RESPONSE_MALFORMED;
Ronnie Sahlbergddf83af2018-08-30 10:12:59 +1000632 /*
633 * Trying to handle/dequeue a mid after the send_recv()
634 * function has finished processing it is a bug.
635 */
636 if (mid->mid_flags & MID_DELETED)
Joe Perchesa0a30362020-04-14 22:42:53 -0700637 pr_warn_once("trying to dequeue a deleted mid\n");
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700638 else {
Ronnie Sahlbergddf83af2018-08-30 10:12:59 +1000639 list_del_init(&mid->qhead);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700640 mid->mid_flags |= MID_DELETED;
641 }
Jeff Laytonea1f4502011-10-19 15:29:05 -0400642 spin_unlock(&GlobalMid_Lock);
643}
644
Pavel Shilovsky86a79642019-11-21 11:35:13 -0800645static unsigned int
646smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
647{
648 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
649
650 /*
651 * SMB1 does not use credits.
652 */
653 if (server->vals->header_preamble_size)
654 return 0;
655
656 return le16_to_cpu(shdr->CreditRequest);
657}
658
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400659static void
660handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400661 char *buf, int malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400662{
Pavel Shilovsky316cf942012-05-23 14:31:03 +0400663 if (server->ops->check_trans2 &&
664 server->ops->check_trans2(mid, server, buf, malformed))
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400665 return;
Pavel Shilovsky86a79642019-11-21 11:35:13 -0800666 mid->credits_received = smb2_get_credits_from_hdr(buf, server);
Jeff Laytonea1f4502011-10-19 15:29:05 -0400667 mid->resp_buf = buf;
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400668 mid->large_buf = server->large_buf;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400669 /* Was previous buf put in mpx struct for multi-rsp? */
670 if (!mid->multiRsp) {
671 /* smb buffer will be freed by user thread */
672 if (server->large_buf)
673 server->bigbuf = NULL;
674 else
675 server->smallbuf = NULL;
676 }
Jeff Laytonffc00e22011-10-19 15:29:13 -0400677 dequeue_mid(mid, malformed);
Pavel Shilovskyad69bae2011-08-01 13:19:43 +0400678}
679
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400680static void clean_demultiplex_info(struct TCP_Server_Info *server)
681{
682 int length;
683
684 /* take it off the list, if it's not already */
685 spin_lock(&cifs_tcp_ses_lock);
686 list_del_init(&server->tcp_ses_list);
687 spin_unlock(&cifs_tcp_ses_lock);
688
Paulo Alcantara21225332020-11-28 16:54:02 -0300689 cancel_delayed_work_sync(&server->echo);
690
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400691 spin_lock(&GlobalMid_Lock);
692 server->tcpStatus = CifsExiting;
693 spin_unlock(&GlobalMid_Lock);
694 wake_up_all(&server->response_q);
695
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400696 /* check if we have blocked requests that need to free */
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300697 spin_lock(&server->req_lock);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400698 if (server->credits <= 0)
699 server->credits = 1;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300700 spin_unlock(&server->req_lock);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400701 /*
702 * Although there should not be any requests blocked on this queue it
703 * can not hurt to be paranoid and try to wake up requests that may
704 * haven been blocked when more than 50 at time were on the wire to the
705 * same server - they now will see the session is in exit state and get
706 * out of SendReceive.
707 */
708 wake_up_all(&server->request_q);
709 /* give those requests time to exit */
710 msleep(125);
Long Li050b8c32019-04-04 11:35:42 -0500711 if (cifs_rdma_enabled(server))
712 smbd_destroy(server);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400713 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);
Joe Perchesf96637b2013-05-04 22:12:25 -0500727 cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700728 kref_get(&mid_entry->refcount);
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400729 mid_entry->mid_state = MID_SHUTDOWN;
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400730 list_move(&mid_entry->qhead, &dispose_list);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700731 mid_entry->mid_flags |= MID_DELETED;
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400732 }
733 spin_unlock(&GlobalMid_Lock);
734
735 /* now walk dispose list and issue callbacks */
736 list_for_each_safe(tmp, tmp2, &dispose_list) {
737 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Joe Perchesf96637b2013-05-04 22:12:25 -0500738 cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400739 list_del_init(&mid_entry->qhead);
740 mid_entry->callback(mid_entry);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700741 cifs_mid_q_entry_release(mid_entry);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400742 }
743 /* 1/8th of sec is more than enough time for them to exit */
744 msleep(125);
745 }
746
747 if (!list_empty(&server->pending_mid_q)) {
748 /*
749 * mpx threads have not exited yet give them at least the smb
750 * send timeout time for long ops.
751 *
752 * Due to delays on oplock break requests, we need to wait at
753 * least 45 seconds before giving up on a request getting a
754 * response and going ahead and killing cifsd.
755 */
Joe Perchesf96637b2013-05-04 22:12:25 -0500756 cifs_dbg(FYI, "Wait for exit from demultiplex thread\n");
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400757 msleep(46000);
758 /*
759 * If threads still have not exited they are probably never
760 * coming home not much else we can do but free the memory.
761 */
762 }
763
764 kfree(server->hostname);
765 kfree(server);
766
767 length = atomic_dec_return(&tcpSesAllocCount);
768 if (length > 0)
David Rientjes11d83362015-04-14 15:48:21 -0700769 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400770}
771
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400772static int
Jeff Laytone9097ab2011-10-19 15:29:40 -0400773standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
774{
775 int length;
776 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +1000777 unsigned int pdu_length = server->pdu_size;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400778
779 /* make sure this will fit in a large buffer */
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100780 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
781 server->vals->header_preamble_size) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000782 cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400783 cifs_reconnect(server);
Pavel Shilovsky3fabaa22014-07-10 09:55:52 +0400784 return -ECONNABORTED;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400785 }
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,
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100796 pdu_length - HEADER_SIZE(server) + 1
797 + server->vals->header_preamble_size);
798
Jeff Laytone9097ab2011-10-19 15:29:40 -0400799 if (length < 0)
800 return length;
801 server->total_read += length;
802
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400803 dump_smb(buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400804
Pavel Shilovsky4326ed22016-11-17 15:24:46 -0800805 return cifs_handle_standard(server, mid);
806}
807
808int
809cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
810{
811 char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
812 int length;
813
Jeff Laytone9097ab2011-10-19 15:29:40 -0400814 /*
815 * We know that we received enough to get to the MID as we
816 * checked the pdu_length earlier. Now check to see
817 * if the rest of the header is OK. We borrow the length
818 * var for the rest of the loop to avoid a new stack var.
819 *
820 * 48 bytes is enough to display the header and a little bit
821 * into the payload for debugging purposes.
822 */
Steve French373512e2015-12-18 13:05:30 -0600823 length = server->ops->check_message(buf, server->total_read, server);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400824 if (length != 0)
825 cifs_dump_mem("Bad SMB: ", buf,
826 min_t(unsigned int, server->total_read, 48));
827
Pavel Shilovsky511c54a2017-07-08 14:32:00 -0700828 if (server->ops->is_session_expired &&
829 server->ops->is_session_expired(buf)) {
830 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -0700831 return -1;
832 }
833
Pavel Shilovsky2e44b282012-09-18 16:20:33 -0700834 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -0800835 server->ops->is_status_pending(buf, server))
Pavel Shilovsky2e44b282012-09-18 16:20:33 -0700836 return -1;
837
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500838 if (!mid)
839 return length;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400840
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400841 handle_mid(mid, server, buf, length);
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500842 return 0;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400843}
844
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000845static void
846smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
847{
848 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
Shyam Prasad Ncd7b6992020-11-12 08:56:49 -0800849 int scredits = server->credits;
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000850
851 /*
852 * SMB1 does not use credits.
853 */
854 if (server->vals->header_preamble_size)
855 return;
856
857 if (shdr->CreditRequest) {
858 spin_lock(&server->req_lock);
859 server->credits += le16_to_cpu(shdr->CreditRequest);
860 spin_unlock(&server->req_lock);
861 wake_up(&server->request_q);
Shyam Prasad Ncd7b6992020-11-12 08:56:49 -0800862
863 trace_smb3_add_credits(server->CurrentMid,
864 server->hostname, scredits,
865 le16_to_cpu(shdr->CreditRequest));
866 cifs_server_dbg(FYI, "%s: added %u credits total=%d\n",
867 __func__, le16_to_cpu(shdr->CreditRequest),
868 scredits);
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000869 }
870}
871
872
Jeff Laytone9097ab2011-10-19 15:29:40 -0400873static int
Al Viro7c97c202011-06-21 08:51:28 -0400874cifs_demultiplex_thread(void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000876 int i, num_mids, length;
Al Viro7c97c202011-06-21 08:51:28 -0400877 struct TCP_Server_Info *server = p;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400878 unsigned int pdu_length;
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000879 unsigned int next_offset;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400880 char *buf = NULL;
Steve Frencha5c3e1c2014-09-16 04:16:19 -0500881 struct task_struct *task_to_wake = NULL;
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000882 struct mid_q_entry *mids[MAX_COMPOUND];
883 char *bufs[MAX_COMPOUND];
Rohith Surabattula8e670f72020-09-18 05:37:28 +0000884 unsigned int noreclaim_flag, num_io_timeout = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Eric Biggersdc920272020-03-08 22:58:20 -0700886 noreclaim_flag = memalloc_noreclaim_save();
Joe Perchesf96637b2013-05-04 22:12:25 -0500887 cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400888
889 length = atomic_inc_return(&tcpSesAllocCount);
890 if (length > 1)
David Rientjes11d83362015-04-14 15:48:21 -0700891 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700893 set_freezable();
Eric W. Biederman33da8e72019-08-16 12:33:54 -0500894 allow_kernel_signal(SIGKILL);
Jeff Layton469ee612008-10-16 18:46:39 +0000895 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700896 if (try_to_freeze())
897 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700898
Jeff Layton2a37ef92011-10-19 15:29:23 -0400899 if (!allocate_buffers(server))
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400900 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700901
Jeff Layton2a37ef92011-10-19 15:29:23 -0400902 server->large_buf = false;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400903 buf = server->smallbuf;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000904 pdu_length = 4; /* enough to get RFC1001 header */
Steve Frenchfda35942011-01-20 18:06:34 +0000905
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400906 length = cifs_read_from_socket(server, buf, pdu_length);
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400907 if (length < 0)
Steve Frenchfda35942011-01-20 18:06:34 +0000908 continue;
Ronnie Sahlberg977b6172018-06-01 10:53:02 +1000909
910 if (server->vals->header_preamble_size == 0)
911 server->total_read = 0;
912 else
913 server->total_read = length;
Steve French67010fb2005-04-28 22:41:09 -0700914
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400915 /*
916 * The right amount was read from socket - 4 bytes,
917 * so we can now interpret the length field.
918 */
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400919 pdu_length = get_rfc1002_length(buf);
Steve French46810cb2005-04-28 22:41:09 -0700920
Joe Perchesf96637b2013-05-04 22:12:25 -0500921 cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400922 if (!is_smb_response(server, buf[0]))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000923 continue;
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000924next_pdu:
925 server->pdu_size = pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700926
Jeff Layton89482a52011-10-19 15:28:57 -0400927 /* make sure we have enough to get to the MID */
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000928 if (server->pdu_size < HEADER_SIZE(server) - 1 -
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100929 server->vals->header_preamble_size) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000930 cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000931 server->pdu_size);
Jeff Layton89482a52011-10-19 15:28:57 -0400932 cifs_reconnect(server);
Jeff Layton89482a52011-10-19 15:28:57 -0400933 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700934 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400935
Jeff Layton89482a52011-10-19 15:28:57 -0400936 /* read down to the MID */
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100937 length = cifs_read_from_socket(server,
938 buf + server->vals->header_preamble_size,
939 HEADER_SIZE(server) - 1
940 - server->vals->header_preamble_size);
Jeff Layton89482a52011-10-19 15:28:57 -0400941 if (length < 0)
942 continue;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400943 server->total_read += length;
Jeff Layton89482a52011-10-19 15:28:57 -0400944
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000945 if (server->ops->next_header) {
946 next_offset = server->ops->next_header(buf);
947 if (next_offset)
948 server->pdu_size = next_offset;
949 }
950
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000951 memset(mids, 0, sizeof(mids));
952 memset(bufs, 0, sizeof(bufs));
953 num_mids = 0;
954
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800955 if (server->ops->is_transform_hdr &&
956 server->ops->receive_transform &&
957 server->ops->is_transform_hdr(buf)) {
958 length = server->ops->receive_transform(server,
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000959 mids,
960 bufs,
961 &num_mids);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800962 } else {
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000963 mids[0] = server->ops->find_mid(server, buf);
964 bufs[0] = buf;
Steve French7af929d2018-10-02 18:54:09 -0500965 num_mids = 1;
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400966
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000967 if (!mids[0] || !mids[0]->receive)
968 length = standard_receive3(server, mids[0]);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800969 else
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000970 length = mids[0]->receive(server, mids[0]);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800971 }
Jeff Layton44d22d82011-10-19 15:29:49 -0400972
Lars Persson696e4202018-06-25 14:05:25 +0200973 if (length < 0) {
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000974 for (i = 0; i < num_mids; i++)
975 if (mids[i])
976 cifs_mid_q_entry_release(mids[i]);
Steve Frenche4eb2952005-04-28 22:41:09 -0700977 continue;
Lars Persson696e4202018-06-25 14:05:25 +0200978 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700979
Rohith Surabattula8e670f72020-09-18 05:37:28 +0000980 if (server->ops->is_status_io_timeout &&
981 server->ops->is_status_io_timeout(buf)) {
982 num_io_timeout++;
983 if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
984 cifs_reconnect(server);
985 num_io_timeout = 0;
986 continue;
987 }
988 }
989
Steve Frenchfda35942011-01-20 18:06:34 +0000990 server->lstrp = jiffies;
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000991
992 for (i = 0; i < num_mids; i++) {
993 if (mids[i] != NULL) {
994 mids[i]->resp_buf_size = server->pdu_size;
Sachin Prabhu38bd4902017-03-03 15:41:38 -0800995
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000996 if (!mids[i]->multiRsp || mids[i]->multiEnd)
997 mids[i]->callback(mids[i]);
Lars Persson696e4202018-06-25 14:05:25 +0200998
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000999 cifs_mid_q_entry_release(mids[i]);
1000 } else if (server->ops->is_oplock_break &&
1001 server->ops->is_oplock_break(bufs[i],
1002 server)) {
Ronnie Sahlbergeca00452019-02-05 12:56:44 +10001003 smb2_add_credits_from_hdr(bufs[i], server);
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001004 cifs_dbg(FYI, "Received oplock break\n");
1005 } else {
Joe Perchesa0a30362020-04-14 22:42:53 -07001006 cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
1007 atomic_read(&midCount));
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001008 cifs_dump_mem("Received Data is: ", bufs[i],
1009 HEADER_SIZE(server));
Ronnie Sahlberg3e272572019-07-06 06:43:08 +10001010 smb2_add_credits_from_hdr(bufs[i], server);
Steve French39798772006-05-31 22:40:51 +00001011#ifdef CONFIG_CIFS_DEBUG2
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001012 if (server->ops->dump_detail)
1013 server->ops->dump_detail(bufs[i],
1014 server);
1015 cifs_dump_mids(server);
Steve French39798772006-05-31 22:40:51 +00001016#endif /* CIFS_DEBUG2 */
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001017 }
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +10001018 }
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001019
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +10001020 if (pdu_length > server->pdu_size) {
1021 if (!allocate_buffers(server))
1022 continue;
1023 pdu_length -= server->pdu_size;
1024 server->total_read = 0;
1025 server->large_buf = false;
1026 buf = server->smallbuf;
1027 goto next_pdu;
Steve Frenche4eb2952005-04-28 22:41:09 -07001028 }
1029 } /* end while !EXITING */
1030
Justin P. Mattockfd62cb72011-02-24 22:15:02 -08001031 /* buffer usually freed in free_mid - need to free it here on exit */
Jeff Layton2a37ef92011-10-19 15:29:23 -04001032 cifs_buf_release(server->bigbuf);
1033 if (server->smallbuf) /* no sense logging a debug message if NULL */
1034 cifs_small_buf_release(server->smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001036 task_to_wake = xchg(&server->tsk, NULL);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +04001037 clean_demultiplex_info(server);
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001038
1039 /* if server->tsk was NULL then wait for a signal before exiting */
1040 if (!task_to_wake) {
1041 set_current_state(TASK_INTERRUPTIBLE);
1042 while (!signal_pending(current)) {
1043 schedule();
1044 set_current_state(TASK_INTERRUPTIBLE);
1045 }
1046 set_current_state(TASK_RUNNING);
1047 }
1048
Eric Biggersdc920272020-03-08 22:58:20 -07001049 memalloc_noreclaim_restore(noreclaim_flag);
Jeff Layton0468a2c2008-12-01 07:09:35 -05001050 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051}
1052
Steve Frenchbc044992020-12-11 19:48:26 -06001053/**
1054 * Returns true if srcaddr isn't specified and rhs isn't specified, or
1055 * if srcaddr is specified and matches the IP address of the rhs argument
Ben Greear3eb9a882010-09-01 17:06:02 -07001056 */
Paulo Alcantarae4af35f2020-05-19 15:38:28 -03001057bool
1058cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
Ben Greear3eb9a882010-09-01 17:06:02 -07001059{
1060 switch (srcaddr->sa_family) {
1061 case AF_UNSPEC:
1062 return (rhs->sa_family == AF_UNSPEC);
1063 case AF_INET: {
1064 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1065 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1066 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1067 }
1068 case AF_INET6: {
1069 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
Nickolai Zeldoviche3e27752013-01-16 21:36:17 -05001070 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
Ben Greear3eb9a882010-09-01 17:06:02 -07001071 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1072 }
1073 default:
1074 WARN_ON(1);
1075 return false; /* don't expect to be here */
1076 }
1077}
1078
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001079/*
1080 * If no port is specified in addr structure, we try to match with 445 port
1081 * and if it fails - with 139 ports. It should be called only if address
1082 * families of server and addr are equal.
1083 */
1084static bool
1085match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
1086{
Steve French6da97912011-03-13 18:55:55 +00001087 __be16 port, *sport;
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001088
Long Li3b249112019-05-15 14:09:04 -07001089 /* SMBDirect manages its own ports, don't match it here */
1090 if (server->rdma)
1091 return true;
1092
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001093 switch (addr->sa_family) {
1094 case AF_INET:
1095 sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
1096 port = ((struct sockaddr_in *) addr)->sin_port;
1097 break;
1098 case AF_INET6:
1099 sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
1100 port = ((struct sockaddr_in6 *) addr)->sin6_port;
1101 break;
1102 default:
1103 WARN_ON(1);
1104 return false;
1105 }
1106
1107 if (!port) {
1108 port = htons(CIFS_PORT);
1109 if (port == *sport)
1110 return true;
1111
1112 port = htons(RFC1001_PORT);
1113 }
1114
1115 return port == *sport;
1116}
Ben Greear3eb9a882010-09-01 17:06:02 -07001117
1118static bool
1119match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1120 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
Jeff Layton45151482010-07-06 20:43:02 -04001122 switch (addr->sa_family) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001123 case AF_INET: {
1124 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1125 struct sockaddr_in *srv_addr4 =
1126 (struct sockaddr_in *)&server->dstaddr;
1127
1128 if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
Jeff Layton45151482010-07-06 20:43:02 -04001129 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001130 break;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001131 }
1132 case AF_INET6: {
1133 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1134 struct sockaddr_in6 *srv_addr6 =
1135 (struct sockaddr_in6 *)&server->dstaddr;
1136
Jeff Layton45151482010-07-06 20:43:02 -04001137 if (!ipv6_addr_equal(&addr6->sin6_addr,
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001138 &srv_addr6->sin6_addr))
Jeff Layton45151482010-07-06 20:43:02 -04001139 return false;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001140 if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
Jeff Layton45151482010-07-06 20:43:02 -04001141 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001142 break;
1143 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001144 default:
1145 WARN_ON(1);
1146 return false; /* don't expect to be here */
1147 }
Jeff Layton45151482010-07-06 20:43:02 -04001148
Paulo Alcantarae4af35f2020-05-19 15:38:28 -03001149 if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr))
Ben Greear3eb9a882010-09-01 17:06:02 -07001150 return false;
1151
Jeff Layton45151482010-07-06 20:43:02 -04001152 return true;
1153}
1154
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001155static bool
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001156match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001157{
Jeff Layton3f618222013-06-12 19:52:14 -05001158 /*
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001159 * The select_sectype function should either return the ctx->sectype
Jeff Layton3f618222013-06-12 19:52:14 -05001160 * that was specified, or "Unspecified" if that sectype was not
1161 * compatible with the given NEGOTIATE request.
1162 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001163 if (server->ops->select_sectype(server, ctx->sectype)
Sachin Prabhuef65aae2017-01-18 15:35:57 +05301164 == Unspecified)
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001165 return false;
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001166
Jeff Layton3f618222013-06-12 19:52:14 -05001167 /*
1168 * Now check if signing mode is acceptable. No need to check
1169 * global_secflags at this point since if MUST_SIGN is set then
1170 * the server->sign had better be too.
1171 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001172 if (ctx->sign && !server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04001173 return false;
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001174
1175 return true;
1176}
1177
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001178static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001179{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001180 struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
Jeff Layton9fa114f2012-11-26 11:09:57 -05001181
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001182 if (ctx->nosharesock)
Jeff Laytona0b3df52013-05-24 07:40:59 -04001183 return 0;
1184
Steve French43cdae82019-06-13 14:26:49 -05001185 /* If multidialect negotiation see if existing sessions match one */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001186 if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
Steve French43cdae82019-06-13 14:26:49 -05001187 if (server->vals->protocol_id < SMB30_PROT_ID)
1188 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001189 } else if (strcmp(ctx->vals->version_string,
Steve French43cdae82019-06-13 14:26:49 -05001190 SMBDEFAULT_VERSION_STRING) == 0) {
1191 if (server->vals->protocol_id < SMB21_PROT_ID)
1192 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001193 } else if ((server->vals != ctx->vals) || (server->ops != ctx->ops))
Jeff Layton23db65f2012-05-15 12:20:51 -04001194 return 0;
1195
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001196 if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
1197 return 0;
1198
1199 if (!match_address(server, addr,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001200 (struct sockaddr *)&ctx->srcaddr))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001201 return 0;
1202
1203 if (!match_port(server, addr))
1204 return 0;
1205
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001206 if (!match_security(server, ctx))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001207 return 0;
1208
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001209 if (server->echo_interval != ctx->echo_interval * HZ)
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001210 return 0;
1211
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001212 if (server->rdma != ctx->rdma)
Long Li8339dd32017-11-07 01:54:55 -07001213 return 0;
1214
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001215 if (server->ignore_signature != ctx->ignore_signature)
Steve French4f5c10f2019-09-03 21:18:49 -05001216 return 0;
1217
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001218 if (server->min_offload != ctx->min_offload)
Steve French563317e2019-09-08 23:22:02 -05001219 return 0;
1220
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001221 return 1;
1222}
1223
Paulo Alcantara54be1f62018-11-14 16:01:21 -02001224struct TCP_Server_Info *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001225cifs_find_tcp_session(struct smb3_fs_context *ctx)
Jeff Layton45151482010-07-06 20:43:02 -04001226{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001227 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301229 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001230 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Paulo Alcantara (SUSE)3345bb42019-12-04 11:25:06 -03001231 /*
1232 * Skip ses channels since they're only handled in lower layers
1233 * (e.g. cifs_send_recv).
1234 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001235 if (server->is_channel || !match_server(server, ctx))
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001236 continue;
1237
Jeff Laytone7ddee92008-11-14 13:44:38 -05001238 ++server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301239 spin_unlock(&cifs_tcp_ses_lock);
Joe Perchesf96637b2013-05-04 22:12:25 -05001240 cifs_dbg(FYI, "Existing tcp session with server found\n");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001241 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301243 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 return NULL;
1245}
1246
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001247void
1248cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001250 struct task_struct *task;
1251
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301252 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001253 if (--server->srv_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301254 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001255 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001257
Rob Landleyf1d0c992011-01-22 15:44:05 -06001258 put_net(cifs_net_ns(server));
1259
Jeff Laytone7ddee92008-11-14 13:44:38 -05001260 list_del_init(&server->tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301261 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001262
Jeff Laytonc74093b2011-01-11 07:24:23 -05001263 cancel_delayed_work_sync(&server->echo);
1264
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001265 if (from_reconnect)
1266 /*
1267 * Avoid deadlock here: reconnect work calls
1268 * cifs_put_tcp_session() at its end. Need to be sure
1269 * that reconnect work does nothing with server pointer after
1270 * that step.
1271 */
1272 cancel_delayed_work(&server->reconnect);
1273 else
1274 cancel_delayed_work_sync(&server->reconnect);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001275
Jeff Laytone7ddee92008-11-14 13:44:38 -05001276 spin_lock(&GlobalMid_Lock);
1277 server->tcpStatus = CifsExiting;
1278 spin_unlock(&GlobalMid_Lock);
1279
Pavel Shilovsky026e93d2016-11-03 16:47:37 -07001280 cifs_crypto_secmech_release(server);
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301281 cifs_fscache_release_client_cookie(server);
1282
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05001283 kfree(server->session_key.response);
1284 server->session_key.response = NULL;
1285 server->session_key.len = 0;
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001286
1287 task = xchg(&server->tsk, NULL);
1288 if (task)
Eric W. Biederman72abe3b2019-05-15 12:33:50 -05001289 send_sig(SIGKILL, task, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290}
1291
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001292struct TCP_Server_Info *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001293cifs_get_tcp_session(struct smb3_fs_context *ctx)
Jeff Layton63c038c2008-12-01 18:41:46 -05001294{
1295 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Layton63c038c2008-12-01 18:41:46 -05001296 int rc;
1297
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001298 cifs_dbg(FYI, "UNC: %s\n", ctx->UNC);
Jeff Layton63c038c2008-12-01 18:41:46 -05001299
1300 /* see if we already have a matching tcp_ses */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001301 tcp_ses = cifs_find_tcp_session(ctx);
Jeff Layton63c038c2008-12-01 18:41:46 -05001302 if (tcp_ses)
1303 return tcp_ses;
1304
1305 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1306 if (!tcp_ses) {
1307 rc = -ENOMEM;
1308 goto out_err;
1309 }
1310
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001311 tcp_ses->ops = ctx->ops;
1312 tcp_ses->vals = ctx->vals;
Rob Landleyf1d0c992011-01-22 15:44:05 -06001313 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001314 tcp_ses->hostname = extract_hostname(ctx->UNC);
Jeff Layton63c038c2008-12-01 18:41:46 -05001315 if (IS_ERR(tcp_ses->hostname)) {
1316 rc = PTR_ERR(tcp_ses->hostname);
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001317 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001318 }
1319
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001320 tcp_ses->noblockcnt = ctx->rootfs;
1321 tcp_ses->noblocksnd = ctx->noblocksnd || ctx->rootfs;
1322 tcp_ses->noautotune = ctx->noautotune;
1323 tcp_ses->tcp_nodelay = ctx->sockopt_tcp_nodelay;
1324 tcp_ses->rdma = ctx->rdma;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +03001325 tcp_ses->in_flight = 0;
Steve French1b63f182019-09-09 22:57:11 -05001326 tcp_ses->max_in_flight = 0;
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04001327 tcp_ses->credits = 1;
Jeff Layton63c038c2008-12-01 18:41:46 -05001328 init_waitqueue_head(&tcp_ses->response_q);
1329 init_waitqueue_head(&tcp_ses->request_q);
1330 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1331 mutex_init(&tcp_ses->srv_mutex);
1332 memcpy(tcp_ses->workstation_RFC1001_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001333 ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Jeff Layton63c038c2008-12-01 18:41:46 -05001334 memcpy(tcp_ses->server_RFC1001_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001335 ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05001336 tcp_ses->session_estab = false;
Jeff Layton63c038c2008-12-01 18:41:46 -05001337 tcp_ses->sequence_number = 0;
Pavel Shilovsky5b964852019-01-18 11:30:26 -08001338 tcp_ses->reconnect_instance = 1;
Steve Frenchfda35942011-01-20 18:06:34 +00001339 tcp_ses->lstrp = jiffies;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001340 tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
Jeff Layton58fa0152012-05-01 17:41:16 -04001341 spin_lock_init(&tcp_ses->req_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001342 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1343 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001344 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001345 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
1346 mutex_init(&tcp_ses->reconnect_mutex);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001347 memcpy(&tcp_ses->srcaddr, &ctx->srcaddr,
Jeff Layton9fa114f2012-11-26 11:09:57 -05001348 sizeof(tcp_ses->srcaddr));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001349 memcpy(&tcp_ses->dstaddr, &ctx->dstaddr,
Jeff Layton9fa114f2012-11-26 11:09:57 -05001350 sizeof(tcp_ses->dstaddr));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001351 if (ctx->use_client_guid)
1352 memcpy(tcp_ses->client_guid, ctx->client_guid,
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001353 SMB2_CLIENT_GUID_SIZE);
1354 else
1355 generate_random_uuid(tcp_ses->client_guid);
Jeff Layton63c038c2008-12-01 18:41:46 -05001356 /*
1357 * at this point we are the only ones with the pointer
1358 * to the struct since the kernel thread not created yet
1359 * no need to spinlock this init of tcpStatus or srv_count
1360 */
1361 tcp_ses->tcpStatus = CifsNew;
1362 ++tcp_ses->srv_count;
1363
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001364 if (ctx->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
1365 ctx->echo_interval <= SMB_ECHO_INTERVAL_MAX)
1366 tcp_ses->echo_interval = ctx->echo_interval * HZ;
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001367 else
1368 tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
Long Li2f894642017-11-22 17:38:34 -07001369 if (tcp_ses->rdma) {
1370#ifndef CONFIG_CIFS_SMB_DIRECT
1371 cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n");
1372 rc = -ENOENT;
1373 goto out_err_crypto_release;
1374#endif
1375 tcp_ses->smbd_conn = smbd_get_connection(
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001376 tcp_ses, (struct sockaddr *)&ctx->dstaddr);
Long Li2f894642017-11-22 17:38:34 -07001377 if (tcp_ses->smbd_conn) {
1378 cifs_dbg(VFS, "RDMA transport established\n");
1379 rc = 0;
1380 goto smbd_connected;
1381 } else {
1382 rc = -ENOENT;
1383 goto out_err_crypto_release;
1384 }
1385 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001386 rc = ip_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001387 if (rc < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001388 cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001389 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001390 }
Long Li2f894642017-11-22 17:38:34 -07001391smbd_connected:
Jeff Layton63c038c2008-12-01 18:41:46 -05001392 /*
1393 * since we're in a cifs function already, we know that
1394 * this will succeed. No need for try_module_get().
1395 */
1396 __module_get(THIS_MODULE);
Al Viro7c97c202011-06-21 08:51:28 -04001397 tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
Jeff Layton63c038c2008-12-01 18:41:46 -05001398 tcp_ses, "cifsd");
1399 if (IS_ERR(tcp_ses->tsk)) {
1400 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesf96637b2013-05-04 22:12:25 -05001401 cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05001402 module_put(THIS_MODULE);
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001403 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001404 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001405 tcp_ses->min_offload = ctx->min_offload;
Steve Frenchfd88ce92011-04-12 01:01:14 +00001406 tcp_ses->tcpStatus = CifsNeedNegotiate;
Jeff Layton63c038c2008-12-01 18:41:46 -05001407
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02001408 tcp_ses->nr_targets = 1;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001409 tcp_ses->ignore_signature = ctx->ignore_signature;
Jeff Layton63c038c2008-12-01 18:41:46 -05001410 /* thread spawned, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301411 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001412 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301413 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001414
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301415 cifs_fscache_get_client_cookie(tcp_ses);
1416
Jeff Laytonc74093b2011-01-11 07:24:23 -05001417 /* queue echo request delayed work */
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001418 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001419
Jeff Layton63c038c2008-12-01 18:41:46 -05001420 return tcp_ses;
1421
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001422out_err_crypto_release:
Pavel Shilovsky026e93d2016-11-03 16:47:37 -07001423 cifs_crypto_secmech_release(tcp_ses);
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05001424
Rob Landleyf1d0c992011-01-22 15:44:05 -06001425 put_net(cifs_net_ns(tcp_ses));
1426
Jeff Layton63c038c2008-12-01 18:41:46 -05001427out_err:
1428 if (tcp_ses) {
Steve French8347a5c2009-10-06 18:31:29 +00001429 if (!IS_ERR(tcp_ses->hostname))
1430 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05001431 if (tcp_ses->ssocket)
1432 sock_release(tcp_ses->ssocket);
1433 kfree(tcp_ses);
1434 }
1435 return ERR_PTR(rc);
1436}
1437
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001438static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001439{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001440 if (ctx->sectype != Unspecified &&
1441 ctx->sectype != ses->sectype)
Jeff Layton3f618222013-06-12 19:52:14 -05001442 return 0;
1443
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001444 /*
1445 * If an existing session is limited to less channels than
1446 * requested, it should not be reused
1447 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001448 if (ses->chan_max < ctx->max_channels)
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001449 return 0;
1450
Jeff Layton3f618222013-06-12 19:52:14 -05001451 switch (ses->sectype) {
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001452 case Kerberos:
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001453 if (!uid_eq(ctx->cred_uid, ses->cred_uid))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001454 return 0;
1455 break;
1456 default:
Jeff Layton04febab2012-01-17 16:09:15 -05001457 /* NULL username means anonymous session */
1458 if (ses->user_name == NULL) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001459 if (!ctx->nullauth)
Jeff Layton04febab2012-01-17 16:09:15 -05001460 return 0;
1461 break;
1462 }
1463
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001464 /* anything else takes username/password */
Jeff Layton04febab2012-01-17 16:09:15 -05001465 if (strncmp(ses->user_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001466 ctx->username ? ctx->username : "",
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001467 CIFS_MAX_USERNAME_LEN))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001468 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001469 if ((ctx->username && strlen(ctx->username) != 0) &&
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001470 ses->password != NULL &&
1471 strncmp(ses->password,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001472 ctx->password ? ctx->password : "",
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001473 CIFS_MAX_PASSWORD_LEN))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001474 return 0;
1475 }
1476 return 1;
1477}
1478
Aurelien Aptelb327a712018-01-24 13:46:10 +01001479/**
1480 * cifs_setup_ipc - helper to setup the IPC tcon for the session
1481 *
1482 * A new IPC connection is made and stored in the session
1483 * tcon_ipc. The IPC tcon has the same lifetime as the session.
1484 */
1485static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001486cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Aurelien Aptelb327a712018-01-24 13:46:10 +01001487{
1488 int rc = 0, xid;
1489 struct cifs_tcon *tcon;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001490 char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
1491 bool seal = false;
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001492 struct TCP_Server_Info *server = ses->server;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001493
1494 /*
1495 * If the mount request that resulted in the creation of the
1496 * session requires encryption, force IPC to be encrypted too.
1497 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001498 if (ctx->seal) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001499 if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
Aurelien Aptelb327a712018-01-24 13:46:10 +01001500 seal = true;
1501 else {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001502 cifs_server_dbg(VFS,
Aurelien Aptelb327a712018-01-24 13:46:10 +01001503 "IPC: server doesn't support encryption\n");
1504 return -EOPNOTSUPP;
1505 }
1506 }
1507
1508 tcon = tconInfoAlloc();
1509 if (tcon == NULL)
1510 return -ENOMEM;
1511
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001512 scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001513
Aurelien Aptelb327a712018-01-24 13:46:10 +01001514 xid = get_xid();
1515 tcon->ses = ses;
1516 tcon->ipc = true;
1517 tcon->seal = seal;
Ronnie Sahlberg6fd4ea82020-12-14 16:40:21 +10001518 rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001519 free_xid(xid);
1520
1521 if (rc) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001522 cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001523 tconInfoFree(tcon);
1524 goto out;
1525 }
1526
1527 cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
1528
1529 ses->tcon_ipc = tcon;
1530out:
Aurelien Aptelb327a712018-01-24 13:46:10 +01001531 return rc;
1532}
1533
1534/**
1535 * cifs_free_ipc - helper to release the session IPC tcon
1536 *
1537 * Needs to be called everytime a session is destroyed
1538 */
1539static int
1540cifs_free_ipc(struct cifs_ses *ses)
1541{
1542 int rc = 0, xid;
1543 struct cifs_tcon *tcon = ses->tcon_ipc;
1544
1545 if (tcon == NULL)
1546 return 0;
1547
1548 if (ses->server->ops->tree_disconnect) {
1549 xid = get_xid();
1550 rc = ses->server->ops->tree_disconnect(xid, tcon);
1551 free_xid(xid);
1552 }
1553
1554 if (rc)
1555 cifs_dbg(FYI, "failed to disconnect IPC tcon (rc=%d)\n", rc);
1556
1557 tconInfoFree(tcon);
1558 ses->tcon_ipc = NULL;
1559 return rc;
1560}
1561
Steve French96daf2b2011-05-27 04:34:02 +00001562static struct cifs_ses *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001563cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
Steve French96daf2b2011-05-27 04:34:02 +00001565 struct cifs_ses *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301567 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04001568 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001569 if (ses->status == CifsExiting)
1570 continue;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001571 if (!match_session(ses, ctx))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001572 continue;
Jeff Layton14fbf502008-11-14 13:53:46 -05001573 ++ses->ses_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301574 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001575 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301577 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return NULL;
1579}
1580
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03001581void cifs_put_smb_ses(struct cifs_ses *ses)
Jeff Layton14fbf502008-11-14 13:53:46 -05001582{
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001583 unsigned int rc, xid;
Jeff Layton14fbf502008-11-14 13:53:46 -05001584 struct TCP_Server_Info *server = ses->server;
1585
Joe Perchesf96637b2013-05-04 22:12:25 -05001586 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001587
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301588 spin_lock(&cifs_tcp_ses_lock);
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001589 if (ses->status == CifsExiting) {
1590 spin_unlock(&cifs_tcp_ses_lock);
1591 return;
1592 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001593 if (--ses->ses_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301594 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001595 return;
1596 }
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001597 if (ses->status == CifsGood)
1598 ses->status = CifsExiting;
1599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001600
Aurelien Aptelb327a712018-01-24 13:46:10 +01001601 cifs_free_ipc(ses);
1602
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001603 if (ses->status == CifsExiting && server->ops->logoff) {
1604 xid = get_xid();
1605 rc = server->ops->logoff(xid, ses);
1606 if (rc)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001607 cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001608 __func__, rc);
1609 _free_xid(xid);
1610 }
1611
1612 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001613 list_del_init(&ses->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301614 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001615
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001616 /* close any extra channels */
1617 if (ses->chan_count > 1) {
1618 int i;
1619
1620 for (i = 1; i < ses->chan_count; i++)
1621 cifs_put_tcp_session(ses->chans[i].server, 0);
1622 }
1623
Jeff Layton14fbf502008-11-14 13:53:46 -05001624 sesInfoFree(ses);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001625 cifs_put_tcp_session(server, 0);
Jeff Layton14fbf502008-11-14 13:53:46 -05001626}
1627
Jeff Layton8a8798a2012-01-17 16:09:15 -05001628#ifdef CONFIG_KEYS
1629
Chen Gang057d6332013-07-19 09:01:36 +08001630/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
1631#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
Jeff Layton8a8798a2012-01-17 16:09:15 -05001632
1633/* Populate username and pw fields from keyring if possible */
1634static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001635cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
Jeff Layton8a8798a2012-01-17 16:09:15 -05001636{
1637 int rc = 0;
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001638 int is_domain = 0;
David Howells146aa8b2015-10-21 14:04:48 +01001639 const char *delim, *payload;
1640 char *desc;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001641 ssize_t len;
1642 struct key *key;
1643 struct TCP_Server_Info *server = ses->server;
1644 struct sockaddr_in *sa;
1645 struct sockaddr_in6 *sa6;
David Howells146aa8b2015-10-21 14:04:48 +01001646 const struct user_key_payload *upayload;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001647
1648 desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
1649 if (!desc)
1650 return -ENOMEM;
1651
1652 /* try to find an address key first */
1653 switch (server->dstaddr.ss_family) {
1654 case AF_INET:
1655 sa = (struct sockaddr_in *)&server->dstaddr;
1656 sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
1657 break;
1658 case AF_INET6:
1659 sa6 = (struct sockaddr_in6 *)&server->dstaddr;
1660 sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
1661 break;
1662 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001663 cifs_dbg(FYI, "Bad ss_family (%hu)\n",
1664 server->dstaddr.ss_family);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001665 rc = -EINVAL;
1666 goto out_err;
1667 }
1668
Joe Perchesf96637b2013-05-04 22:12:25 -05001669 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
Linus Torvalds028db3e2019-07-10 18:43:43 -07001670 key = request_key(&key_type_logon, desc, "");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001671 if (IS_ERR(key)) {
1672 if (!ses->domainName) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001673 cifs_dbg(FYI, "domainName is NULL\n");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001674 rc = PTR_ERR(key);
1675 goto out_err;
1676 }
1677
1678 /* didn't work, try to find a domain key */
1679 sprintf(desc, "cifs:d:%s", ses->domainName);
Joe Perchesf96637b2013-05-04 22:12:25 -05001680 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
Linus Torvalds028db3e2019-07-10 18:43:43 -07001681 key = request_key(&key_type_logon, desc, "");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001682 if (IS_ERR(key)) {
1683 rc = PTR_ERR(key);
1684 goto out_err;
1685 }
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001686 is_domain = 1;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001687 }
1688
1689 down_read(&key->sem);
David Howells0837e492017-03-01 15:11:23 +00001690 upayload = user_key_payload_locked(key);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001691 if (IS_ERR_OR_NULL(upayload)) {
Jeff Layton4edc53c2012-02-07 06:30:51 -05001692 rc = upayload ? PTR_ERR(upayload) : -EINVAL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001693 goto out_key_put;
1694 }
1695
1696 /* find first : in payload */
David Howells146aa8b2015-10-21 14:04:48 +01001697 payload = upayload->data;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001698 delim = strnchr(payload, upayload->datalen, ':');
Joe Perchesf96637b2013-05-04 22:12:25 -05001699 cifs_dbg(FYI, "payload=%s\n", payload);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001700 if (!delim) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001701 cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
1702 upayload->datalen);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001703 rc = -EINVAL;
1704 goto out_key_put;
1705 }
1706
1707 len = delim - payload;
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001708 if (len > CIFS_MAX_USERNAME_LEN || len <= 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001709 cifs_dbg(FYI, "Bad value from username search (len=%zd)\n",
1710 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001711 rc = -EINVAL;
1712 goto out_key_put;
1713 }
1714
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001715 ctx->username = kstrndup(payload, len, GFP_KERNEL);
1716 if (!ctx->username) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001717 cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n",
1718 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001719 rc = -ENOMEM;
1720 goto out_key_put;
1721 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001722 cifs_dbg(FYI, "%s: username=%s\n", __func__, ctx->username);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001723
1724 len = key->datalen - (len + 1);
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001725 if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001726 cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001727 rc = -EINVAL;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001728 kfree(ctx->username);
1729 ctx->username = NULL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001730 goto out_key_put;
1731 }
1732
1733 ++delim;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001734 ctx->password = kstrndup(delim, len, GFP_KERNEL);
1735 if (!ctx->password) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001736 cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
1737 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001738 rc = -ENOMEM;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001739 kfree(ctx->username);
1740 ctx->username = NULL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001741 goto out_key_put;
1742 }
1743
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001744 /*
1745 * If we have a domain key then we must set the domainName in the
1746 * for the request.
1747 */
1748 if (is_domain && ses->domainName) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001749 ctx->domainname = kstrndup(ses->domainName,
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001750 strlen(ses->domainName),
1751 GFP_KERNEL);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001752 if (!ctx->domainname) {
Joe Perchesa0a30362020-04-14 22:42:53 -07001753 cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
1754 len);
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001755 rc = -ENOMEM;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001756 kfree(ctx->username);
1757 ctx->username = NULL;
1758 kfree_sensitive(ctx->password);
1759 ctx->password = NULL;
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001760 goto out_key_put;
1761 }
1762 }
1763
Jeff Layton8a8798a2012-01-17 16:09:15 -05001764out_key_put:
1765 up_read(&key->sem);
1766 key_put(key);
1767out_err:
1768 kfree(desc);
Joe Perchesf96637b2013-05-04 22:12:25 -05001769 cifs_dbg(FYI, "%s: returning %d\n", __func__, rc);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001770 return rc;
1771}
1772#else /* ! CONFIG_KEYS */
1773static inline int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001774cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)),
Jeff Layton8a8798a2012-01-17 16:09:15 -05001775 struct cifs_ses *ses __attribute__((unused)))
1776{
1777 return -ENOSYS;
1778}
1779#endif /* CONFIG_KEYS */
1780
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001781/**
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001782 * cifs_get_smb_ses - get a session matching @ctx data from @server
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001783 *
1784 * This function assumes it is being called from cifs_mount() where we
1785 * already got a server reference (server refcount +1). See
1786 * cifs_get_tcon() for refcount explanations.
1787 */
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03001788struct cifs_ses *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001789cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Jeff Layton36988c72010-04-24 07:57:43 -04001790{
Pavel Shilovsky286170a2012-05-25 10:43:58 +04001791 int rc = -ENOMEM;
1792 unsigned int xid;
Steve French96daf2b2011-05-27 04:34:02 +00001793 struct cifs_ses *ses;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001794 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
1795 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
Jeff Layton36988c72010-04-24 07:57:43 -04001796
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001797 xid = get_xid();
Jeff Layton36988c72010-04-24 07:57:43 -04001798
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001799 ses = cifs_find_smb_ses(server, ctx);
Jeff Layton36988c72010-04-24 07:57:43 -04001800 if (ses) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001801 cifs_dbg(FYI, "Existing smb sess found (status=%d)\n",
1802 ses->status);
Jeff Layton36988c72010-04-24 07:57:43 -04001803
Jeff Layton36988c72010-04-24 07:57:43 -04001804 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001805 rc = cifs_negotiate_protocol(xid, ses);
1806 if (rc) {
1807 mutex_unlock(&ses->session_mutex);
1808 /* problem -- put our ses reference */
1809 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001810 free_xid(xid);
Jeff Layton198b5682010-04-24 07:57:48 -04001811 return ERR_PTR(rc);
1812 }
Jeff Layton36988c72010-04-24 07:57:43 -04001813 if (ses->need_reconnect) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001814 cifs_dbg(FYI, "Session needs reconnect\n");
Jeff Layton36988c72010-04-24 07:57:43 -04001815 rc = cifs_setup_session(xid, ses,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001816 ctx->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04001817 if (rc) {
1818 mutex_unlock(&ses->session_mutex);
1819 /* problem -- put our reference */
1820 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001821 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001822 return ERR_PTR(rc);
1823 }
1824 }
1825 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04001826
1827 /* existing SMB ses has a server reference already */
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001828 cifs_put_tcp_session(server, 0);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001829 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001830 return ses;
1831 }
1832
Joe Perchesf96637b2013-05-04 22:12:25 -05001833 cifs_dbg(FYI, "Existing smb sess not found\n");
Jeff Layton36988c72010-04-24 07:57:43 -04001834 ses = sesInfoAlloc();
1835 if (ses == NULL)
1836 goto get_ses_fail;
1837
1838 /* new SMB session uses our server ref */
1839 ses->server = server;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001840 if (server->dstaddr.ss_family == AF_INET6)
1841 sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001842 else
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001843 sprintf(ses->serverName, "%pI4", &addr->sin_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001844
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001845 if (ctx->username) {
1846 ses->user_name = kstrdup(ctx->username, GFP_KERNEL);
Steve French8727c8a2011-02-25 01:11:56 -06001847 if (!ses->user_name)
1848 goto get_ses_fail;
1849 }
Jeff Layton36988c72010-04-24 07:57:43 -04001850
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001851 /* ctx->password freed at unmount */
1852 if (ctx->password) {
1853 ses->password = kstrdup(ctx->password, GFP_KERNEL);
Jeff Layton36988c72010-04-24 07:57:43 -04001854 if (!ses->password)
1855 goto get_ses_fail;
1856 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001857 if (ctx->domainname) {
1858 ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL);
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05001859 if (!ses->domainName)
1860 goto get_ses_fail;
Jeff Layton36988c72010-04-24 07:57:43 -04001861 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001862 if (ctx->domainauto)
1863 ses->domainAuto = ctx->domainauto;
1864 ses->cred_uid = ctx->cred_uid;
1865 ses->linux_uid = ctx->linux_uid;
Steve Frenchd9b94202011-04-12 01:24:57 +00001866
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001867 ses->sectype = ctx->sectype;
1868 ses->sign = ctx->sign;
Jeff Layton36988c72010-04-24 07:57:43 -04001869 mutex_lock(&ses->session_mutex);
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001870
1871 /* add server as first channel */
1872 ses->chans[0].server = server;
1873 ses->chan_count = 1;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001874 ses->chan_max = ctx->multichannel ? ctx->max_channels:1;
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001875
Jeff Layton198b5682010-04-24 07:57:48 -04001876 rc = cifs_negotiate_protocol(xid, ses);
1877 if (!rc)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001878 rc = cifs_setup_session(xid, ses, ctx->local_nls);
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001879
1880 /* each channel uses a different signing key */
1881 memcpy(ses->chans[0].signkey, ses->smb3signingkey,
1882 sizeof(ses->smb3signingkey));
1883
Jeff Layton36988c72010-04-24 07:57:43 -04001884 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00001885 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04001886 goto get_ses_fail;
1887
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001888 /* success, put it on the list and add it as first channel */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301889 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001890 list_add(&ses->smb_ses_list, &server->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301891 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001892
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001893 free_xid(xid);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001894
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001895 cifs_setup_ipc(ses, ctx);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001896
Jeff Layton36988c72010-04-24 07:57:43 -04001897 return ses;
1898
1899get_ses_fail:
1900 sesInfoFree(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001901 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001902 return ERR_PTR(rc);
1903}
1904
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001905static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001906{
1907 if (tcon->tidStatus == CifsExiting)
1908 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001909 if (strncmp(tcon->treeName, ctx->UNC, MAX_TREE_SIZE))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001910 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001911 if (tcon->seal != ctx->seal)
Pavel Shilovskyae6f8dd2016-11-17 13:59:23 -08001912 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001913 if (tcon->snapshot_time != ctx->snapshot_time)
Pavel Shilovskyae6f8dd2016-11-17 13:59:23 -08001914 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001915 if (tcon->handle_timeout != ctx->handle_timeout)
Steve Frenchca567eb2019-03-29 16:31:07 -05001916 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001917 if (tcon->no_lease != ctx->no_lease)
Steve French3e7a02d2019-09-11 21:46:20 -05001918 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001919 if (tcon->nodelete != ctx->nodelete)
Steve French82e93672020-05-19 03:06:57 -05001920 return 0;
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001921 return 1;
1922}
1923
Steve French96daf2b2011-05-27 04:34:02 +00001924static struct cifs_tcon *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001925cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
1927 struct list_head *tmp;
Steve French96daf2b2011-05-27 04:34:02 +00001928 struct cifs_tcon *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301930 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001931 list_for_each(tmp, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +00001932 tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
Paulo Alcantara65303de2020-04-20 19:42:57 -03001933#ifdef CONFIG_CIFS_DFS_UPCALL
1934 if (tcon->dfs_path)
1935 continue;
1936#endif
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001937 if (!match_tcon(tcon, ctx))
Jeff Laytonf1987b42008-11-15 11:12:47 -05001938 continue;
Jeff Laytonf1987b42008-11-15 11:12:47 -05001939 ++tcon->tc_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301940 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 return tcon;
1942 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301943 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 return NULL;
1945}
1946
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001947void
Steve French96daf2b2011-05-27 04:34:02 +00001948cifs_put_tcon(struct cifs_tcon *tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05001949{
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04001950 unsigned int xid;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001951 struct cifs_ses *ses;
Jeff Laytonf1987b42008-11-15 11:12:47 -05001952
Aurelien Aptelb327a712018-01-24 13:46:10 +01001953 /*
1954 * IPC tcon share the lifetime of their session and are
1955 * destroyed in the session put function
1956 */
1957 if (tcon == NULL || tcon->ipc)
1958 return;
1959
1960 ses = tcon->ses;
Joe Perchesf96637b2013-05-04 22:12:25 -05001961 cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301962 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001963 if (--tcon->tc_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301964 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001965 return;
1966 }
1967
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01001968#ifdef CONFIG_CIFS_SWN_UPCALL
1969 if (tcon->use_witness) {
1970 int rc;
1971
1972 rc = cifs_swn_unregister(tcon);
1973 if (rc < 0) {
1974 cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
1975 __func__, rc);
1976 }
1977 }
1978#endif
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06001979
Jeff Laytonf1987b42008-11-15 11:12:47 -05001980 list_del_init(&tcon->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301981 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001982
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001983 xid = get_xid();
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04001984 if (ses->server->ops->tree_disconnect)
1985 ses->server->ops->tree_disconnect(xid, tcon);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001986 _free_xid(xid);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001987
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301988 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00001989 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001990 cifs_put_smb_ses(ses);
1991}
1992
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001993/**
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001994 * cifs_get_tcon - get a tcon matching @ctx data from @ses
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001995 *
1996 * - tcon refcount is the number of mount points using the tcon.
1997 * - ses refcount is the number of tcon using the session.
1998 *
1999 * 1. This function assumes it is being called from cifs_mount() where
2000 * we already got a session reference (ses refcount +1).
2001 *
2002 * 2. Since we're in the context of adding a mount point, the end
2003 * result should be either:
2004 *
2005 * a) a new tcon already allocated with refcount=1 (1 mount point) and
2006 * its session refcount incremented (1 new tcon). This +1 was
2007 * already done in (1).
2008 *
2009 * b) an existing tcon with refcount+1 (add a mount point to it) and
2010 * identical ses refcount (no new tcon). Because of (1) we need to
2011 * decrement the ses refcount.
2012 */
Steve French96daf2b2011-05-27 04:34:02 +00002013static struct cifs_tcon *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002014cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Jeff Laytond00c28d2010-04-24 07:57:44 -04002015{
2016 int rc, xid;
Steve French96daf2b2011-05-27 04:34:02 +00002017 struct cifs_tcon *tcon;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002018
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002019 tcon = cifs_find_tcon(ses, ctx);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002020 if (tcon) {
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01002021 /*
2022 * tcon has refcount already incremented but we need to
2023 * decrement extra ses reference gotten by caller (case b)
2024 */
Joe Perchesf96637b2013-05-04 22:12:25 -05002025 cifs_dbg(FYI, "Found match on UNC path\n");
Jeff Laytond00c28d2010-04-24 07:57:44 -04002026 cifs_put_smb_ses(ses);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002027 return tcon;
2028 }
2029
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002030 if (!ses->server->ops->tree_connect) {
2031 rc = -ENOSYS;
2032 goto out_fail;
2033 }
2034
Jeff Laytond00c28d2010-04-24 07:57:44 -04002035 tcon = tconInfoAlloc();
2036 if (tcon == NULL) {
2037 rc = -ENOMEM;
2038 goto out_fail;
2039 }
2040
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002041 if (ctx->snapshot_time) {
Steve French8b217fe2016-11-11 22:36:20 -06002042 if (ses->server->vals->protocol_id == 0) {
2043 cifs_dbg(VFS,
2044 "Use SMB2 or later for snapshot mount option\n");
2045 rc = -EOPNOTSUPP;
2046 goto out_fail;
2047 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002048 tcon->snapshot_time = ctx->snapshot_time;
Steve French8b217fe2016-11-11 22:36:20 -06002049 }
2050
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002051 if (ctx->handle_timeout) {
Steve Frenchca567eb2019-03-29 16:31:07 -05002052 if (ses->server->vals->protocol_id == 0) {
2053 cifs_dbg(VFS,
2054 "Use SMB2.1 or later for handle timeout option\n");
2055 rc = -EOPNOTSUPP;
2056 goto out_fail;
2057 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002058 tcon->handle_timeout = ctx->handle_timeout;
Steve Frenchca567eb2019-03-29 16:31:07 -05002059 }
2060
Jeff Laytond00c28d2010-04-24 07:57:44 -04002061 tcon->ses = ses;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002062 if (ctx->password) {
2063 tcon->password = kstrdup(ctx->password, GFP_KERNEL);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002064 if (!tcon->password) {
2065 rc = -ENOMEM;
2066 goto out_fail;
2067 }
2068 }
2069
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002070 if (ctx->seal) {
Steve French23657ad2018-04-22 15:14:58 -05002071 if (ses->server->vals->protocol_id == 0) {
2072 cifs_dbg(VFS,
2073 "SMB3 or later required for encryption\n");
2074 rc = -EOPNOTSUPP;
2075 goto out_fail;
2076 } else if (tcon->ses->server->capabilities &
2077 SMB2_GLOBAL_CAP_ENCRYPTION)
2078 tcon->seal = true;
2079 else {
2080 cifs_dbg(VFS, "Encryption is not supported on share\n");
2081 rc = -EOPNOTSUPP;
2082 goto out_fail;
2083 }
2084 }
2085
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002086 if (ctx->linux_ext) {
Steve French8505c8b2018-06-18 14:01:59 -05002087 if (ses->server->posix_ext_supported) {
Steve Frenchb3266142018-05-20 23:41:10 -05002088 tcon->posix_extensions = true;
Joe Perchesa0a30362020-04-14 22:42:53 -07002089 pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
Steve French8505c8b2018-06-18 14:01:59 -05002090 } else {
Joe Perchesa0a30362020-04-14 22:42:53 -07002091 cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
Steve French8505c8b2018-06-18 14:01:59 -05002092 rc = -EOPNOTSUPP;
2093 goto out_fail;
Steve French2fbb5642018-06-12 12:11:31 -05002094 }
Steve Frenchb3266142018-05-20 23:41:10 -05002095 }
Steve Frenchb3266142018-05-20 23:41:10 -05002096
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002097 /*
2098 * BB Do we need to wrap session_mutex around this TCon call and Unix
2099 * SetFS as we do on SessSetup and reconnect?
2100 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002101 xid = get_xid();
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002102 rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon,
2103 ctx->local_nls);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002104 free_xid(xid);
Joe Perchesf96637b2013-05-04 22:12:25 -05002105 cifs_dbg(FYI, "Tcon rc = %d\n", rc);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002106 if (rc)
2107 goto out_fail;
2108
Steve Frenchb618f002015-11-03 09:15:03 -06002109 tcon->use_persistent = false;
2110 /* check if SMB2 or later, CIFS does not support persistent handles */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002111 if (ctx->persistent) {
Steve Frenchb618f002015-11-03 09:15:03 -06002112 if (ses->server->vals->protocol_id == 0) {
2113 cifs_dbg(VFS,
2114 "SMB3 or later required for persistent handles\n");
2115 rc = -EOPNOTSUPP;
2116 goto out_fail;
2117 } else if (ses->server->capabilities &
2118 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
2119 tcon->use_persistent = true;
2120 else /* persistent handles requested but not supported */ {
2121 cifs_dbg(VFS,
2122 "Persistent handles not supported on share\n");
2123 rc = -EOPNOTSUPP;
2124 goto out_fail;
2125 }
2126 } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
2127 && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002128 && (ctx->nopersistent == false)) {
Steve Frenchb618f002015-11-03 09:15:03 -06002129 cifs_dbg(FYI, "enabling persistent handles\n");
2130 tcon->use_persistent = true;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002131 } else if (ctx->resilient) {
Steve French592fafe2015-11-03 10:08:53 -06002132 if (ses->server->vals->protocol_id == 0) {
2133 cifs_dbg(VFS,
2134 "SMB2.1 or later required for resilient handles\n");
2135 rc = -EOPNOTSUPP;
2136 goto out_fail;
2137 }
2138 tcon->use_resilient = true;
Steve Frenchb618f002015-11-03 09:15:03 -06002139 }
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002140#ifdef CONFIG_CIFS_SWN_UPCALL
2141 tcon->use_witness = false;
2142 if (ctx->witness) {
2143 if (ses->server->vals->protocol_id >= SMB30_PROT_ID) {
2144 if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) {
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01002145 /*
2146 * Set witness in use flag in first place
2147 * to retry registration in the echo task
2148 */
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002149 tcon->use_witness = true;
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01002150 /* And try to register immediately */
2151 rc = cifs_swn_register(tcon);
2152 if (rc < 0) {
2153 cifs_dbg(VFS, "Failed to register for witness notifications: %d\n", rc);
2154 goto out_fail;
2155 }
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002156 } else {
2157 /* TODO: try to extend for non-cluster uses (eg multichannel) */
2158 cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n");
2159 rc = -EOPNOTSUPP;
2160 goto out_fail;
2161 }
2162 } else {
2163 cifs_dbg(VFS, "SMB3 or later required for witness option\n");
2164 rc = -EOPNOTSUPP;
2165 goto out_fail;
2166 }
2167 }
2168#endif
Steve Frenchb618f002015-11-03 09:15:03 -06002169
Steve Frenchcae53f72019-09-03 17:49:46 -05002170 /* If the user really knows what they are doing they can override */
2171 if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002172 if (ctx->cache_ro)
Steve Frenchcae53f72019-09-03 17:49:46 -05002173 cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002174 else if (ctx->cache_rw)
Steve Frenchcae53f72019-09-03 17:49:46 -05002175 cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n");
2176 }
2177
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002178 if (ctx->no_lease) {
Kenneth D'souza8fd6e1d2020-05-18 13:01:34 +05302179 if (ses->server->vals->protocol_id == 0) {
2180 cifs_dbg(VFS,
2181 "SMB2 or later required for nolease option\n");
2182 rc = -EOPNOTSUPP;
2183 goto out_fail;
2184 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002185 tcon->no_lease = ctx->no_lease;
Kenneth D'souza8fd6e1d2020-05-18 13:01:34 +05302186 }
2187
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002188 /*
2189 * We can have only one retry value for a connection to a share so for
2190 * resources mounted more than once to the same server share the last
2191 * value passed in for the retry flag is used.
2192 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002193 tcon->retry = ctx->retry;
2194 tcon->nocase = ctx->nocase;
Steve French3c6e65e2020-10-21 00:15:42 -05002195 if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002196 tcon->nohandlecache = ctx->nohandlecache;
Steve French3c6e65e2020-10-21 00:15:42 -05002197 else
Jiapeng Zhong2be449f2021-01-14 17:09:20 +08002198 tcon->nohandlecache = true;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002199 tcon->nodelete = ctx->nodelete;
2200 tcon->local_lease = ctx->local_lease;
Pavel Shilovsky233839b2012-09-19 06:22:45 -07002201 INIT_LIST_HEAD(&tcon->pending_opens);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002202
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302203 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002204 list_add(&tcon->tcon_list, &ses->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302205 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002206
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302207 cifs_fscache_get_super_cookie(tcon);
2208
Jeff Laytond00c28d2010-04-24 07:57:44 -04002209 return tcon;
2210
2211out_fail:
2212 tconInfoFree(tcon);
2213 return ERR_PTR(rc);
2214}
2215
Jeff Layton9d002df2010-10-06 19:51:11 -04002216void
2217cifs_put_tlink(struct tcon_link *tlink)
2218{
2219 if (!tlink || IS_ERR(tlink))
2220 return;
2221
2222 if (!atomic_dec_and_test(&tlink->tl_count) ||
2223 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
2224 tlink->tl_time = jiffies;
2225 return;
2226 }
2227
2228 if (!IS_ERR(tlink_tcon(tlink)))
2229 cifs_put_tcon(tlink_tcon(tlink));
2230 kfree(tlink);
2231 return;
2232}
Jeff Laytond00c28d2010-04-24 07:57:44 -04002233
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002234static int
2235compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2236{
2237 struct cifs_sb_info *old = CIFS_SB(sb);
2238 struct cifs_sb_info *new = mnt_data->cifs_sb;
Paulo Alcantara (SUSE)29fbeb72019-06-18 16:16:02 -03002239 unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
2240 unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002241
2242 if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
2243 return 0;
2244
Paulo Alcantara (SUSE)29fbeb72019-06-18 16:16:02 -03002245 if (old->mnt_cifs_serverino_autodisabled)
2246 newflags &= ~CIFS_MOUNT_SERVER_INUM;
2247
2248 if (oldflags != newflags)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002249 return 0;
2250
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002251 /*
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002252 * We want to share sb only if we don't specify an r/wsize or
2253 * specified r/wsize is greater than or equal to existing one.
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002254 */
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002255 if (new->ctx->wsize && new->ctx->wsize < old->ctx->wsize)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002256 return 0;
2257
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002258 if (new->ctx->rsize && new->ctx->rsize < old->ctx->rsize)
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002259 return 0;
2260
Ronnie Sahlberg8401e932020-12-12 13:40:50 -06002261 if (!uid_eq(old->ctx->linux_uid, new->ctx->linux_uid) ||
2262 !gid_eq(old->ctx->linux_gid, new->ctx->linux_gid))
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002263 return 0;
2264
Ronnie Sahlberg8401e932020-12-12 13:40:50 -06002265 if (old->ctx->file_mode != new->ctx->file_mode ||
2266 old->ctx->dir_mode != new->ctx->dir_mode)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002267 return 0;
2268
2269 if (strcmp(old->local_nls->charset, new->local_nls->charset))
2270 return 0;
2271
Ronnie Sahlbergaf1e40d2020-11-10 12:34:48 +10002272 if (old->ctx->actimeo != new->ctx->actimeo)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002273 return 0;
2274
2275 return 1;
2276}
2277
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002278static int
2279match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2280{
2281 struct cifs_sb_info *old = CIFS_SB(sb);
2282 struct cifs_sb_info *new = mnt_data->cifs_sb;
Ronnie Sahlbergfe129262020-01-22 11:07:56 +10002283 bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
2284 old->prepath;
2285 bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
2286 new->prepath;
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002287
Sachin Prabhucd8c4292017-04-26 14:05:46 +01002288 if (old_set && new_set && !strcmp(new->prepath, old->prepath))
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002289 return 1;
Sachin Prabhucd8c4292017-04-26 14:05:46 +01002290 else if (!old_set && !new_set)
2291 return 1;
2292
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002293 return 0;
2294}
2295
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002296int
2297cifs_match_super(struct super_block *sb, void *data)
2298{
2299 struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002300 struct smb3_fs_context *ctx;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002301 struct cifs_sb_info *cifs_sb;
2302 struct TCP_Server_Info *tcp_srv;
Steve French96daf2b2011-05-27 04:34:02 +00002303 struct cifs_ses *ses;
2304 struct cifs_tcon *tcon;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002305 struct tcon_link *tlink;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002306 int rc = 0;
2307
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002308 spin_lock(&cifs_tcp_ses_lock);
2309 cifs_sb = CIFS_SB(sb);
2310 tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
2311 if (IS_ERR(tlink)) {
2312 spin_unlock(&cifs_tcp_ses_lock);
2313 return rc;
2314 }
2315 tcon = tlink_tcon(tlink);
2316 ses = tcon->ses;
2317 tcp_srv = ses->server;
2318
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002319 ctx = mnt_data->ctx;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002320
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002321 if (!match_server(tcp_srv, ctx) ||
2322 !match_session(ses, ctx) ||
2323 !match_tcon(tcon, ctx) ||
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002324 !match_prepath(sb, mnt_data)) {
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002325 rc = 0;
2326 goto out;
2327 }
2328
2329 rc = compare_mount_options(sb, mnt_data);
2330out:
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002331 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf484b5d02011-07-11 10:16:34 -04002332 cifs_put_tlink(tlink);
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002333 return rc;
2334}
2335
Jeff Layton09e50d52008-07-23 10:11:19 -04002336#ifdef CONFIG_DEBUG_LOCK_ALLOC
2337static struct lock_class_key cifs_key[2];
2338static struct lock_class_key cifs_slock_key[2];
2339
2340static inline void
2341cifs_reclassify_socket4(struct socket *sock)
2342{
2343 struct sock *sk = sock->sk;
Hannes Frederic Sowafafc4e12016-04-08 15:11:27 +02002344 BUG_ON(!sock_allow_reclassification(sk));
Jeff Layton09e50d52008-07-23 10:11:19 -04002345 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2346 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2347}
2348
2349static inline void
2350cifs_reclassify_socket6(struct socket *sock)
2351{
2352 struct sock *sk = sock->sk;
Hannes Frederic Sowafafc4e12016-04-08 15:11:27 +02002353 BUG_ON(!sock_allow_reclassification(sk));
Jeff Layton09e50d52008-07-23 10:11:19 -04002354 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2355 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2356}
2357#else
2358static inline void
2359cifs_reclassify_socket4(struct socket *sock)
2360{
2361}
2362
2363static inline void
2364cifs_reclassify_socket6(struct socket *sock)
2365{
2366}
2367#endif
2368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002370static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371{
Steve French50c2f752007-07-13 00:33:32 +00002372 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Steve French50c2f752007-07-13 00:33:32 +00002374 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 /* mask a nibble at a time and encode */
2376 target[j] = 'A' + (0x0F & (source[i] >> 4));
2377 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002378 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 }
2380
2381}
2382
Ben Greear3eb9a882010-09-01 17:06:02 -07002383static int
2384bind_socket(struct TCP_Server_Info *server)
2385{
2386 int rc = 0;
2387 if (server->srcaddr.ss_family != AF_UNSPEC) {
2388 /* Bind to the specified local IP address */
2389 struct socket *socket = server->ssocket;
2390 rc = socket->ops->bind(socket,
2391 (struct sockaddr *) &server->srcaddr,
2392 sizeof(server->srcaddr));
2393 if (rc < 0) {
2394 struct sockaddr_in *saddr4;
2395 struct sockaddr_in6 *saddr6;
2396 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2397 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2398 if (saddr6->sin6_family == AF_INET6)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002399 cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
Joe Perchesf96637b2013-05-04 22:12:25 -05002400 &saddr6->sin6_addr, rc);
Ben Greear3eb9a882010-09-01 17:06:02 -07002401 else
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002402 cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
Joe Perchesf96637b2013-05-04 22:12:25 -05002403 &saddr4->sin_addr.s_addr, rc);
Ben Greear3eb9a882010-09-01 17:06:02 -07002404 }
2405 }
2406 return rc;
2407}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409static int
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002410ip_rfc1001_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411{
2412 int rc = 0;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002413 /*
2414 * some servers require RFC1001 sessinit before sending
2415 * negprot - BB check reconnection in case where second
2416 * sessinit is sent but no second negprot
2417 */
2418 struct rfc1002_session_packet *ses_init_buf;
2419 struct smb_hdr *smb_buf;
2420 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2421 GFP_KERNEL);
2422 if (ses_init_buf) {
2423 ses_init_buf->trailer.session_req.called_len = 32;
2424
Colin Ian King997152f2016-01-25 16:25:54 +00002425 if (server->server_RFC1001_name[0] != 0)
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002426 rfc1002mangle(ses_init_buf->trailer.
2427 session_req.called_name,
2428 server->server_RFC1001_name,
2429 RFC1001_NAME_LEN_WITH_NULL);
2430 else
2431 rfc1002mangle(ses_init_buf->trailer.
2432 session_req.called_name,
2433 DEFAULT_CIFS_CALLED_NAME,
2434 RFC1001_NAME_LEN_WITH_NULL);
2435
2436 ses_init_buf->trailer.session_req.calling_len = 32;
2437
2438 /*
2439 * calling name ends in null (byte 16) from old smb
2440 * convention.
2441 */
Steve Frenchc85c35f2015-03-27 01:15:02 -05002442 if (server->workstation_RFC1001_name[0] != 0)
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002443 rfc1002mangle(ses_init_buf->trailer.
2444 session_req.calling_name,
2445 server->workstation_RFC1001_name,
2446 RFC1001_NAME_LEN_WITH_NULL);
2447 else
2448 rfc1002mangle(ses_init_buf->trailer.
2449 session_req.calling_name,
2450 "LINUX_CIFS_CLNT",
2451 RFC1001_NAME_LEN_WITH_NULL);
2452
2453 ses_init_buf->trailer.session_req.scope1 = 0;
2454 ses_init_buf->trailer.session_req.scope2 = 0;
2455 smb_buf = (struct smb_hdr *)ses_init_buf;
2456
2457 /* sizeof RFC1002_SESSION_REQUEST with no scope */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002458 smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002459 rc = smb_send(server, smb_buf, 0x44);
2460 kfree(ses_init_buf);
2461 /*
2462 * RFC1001 layer in at least one server
2463 * requires very short break before negprot
2464 * presumably because not expecting negprot
2465 * to follow so fast. This is a simple
2466 * solution that works without
2467 * complicating the code and causes no
2468 * significant slowing down on mount
2469 * for everyone else
2470 */
2471 usleep_range(1000, 2000);
2472 }
2473 /*
2474 * else the negprot may still work without this
2475 * even though malloc failed
2476 */
2477
2478 return rc;
2479}
2480
2481static int
2482generic_ip_connect(struct TCP_Server_Info *server)
2483{
2484 int rc = 0;
Steve French6da97912011-03-13 18:55:55 +00002485 __be16 sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002486 int slen, sfamily;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002487 struct socket *socket = server->ssocket;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002488 struct sockaddr *saddr;
2489
2490 saddr = (struct sockaddr *) &server->dstaddr;
2491
2492 if (server->dstaddr.ss_family == AF_INET6) {
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002493 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr;
2494
2495 sport = ipv6->sin6_port;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002496 slen = sizeof(struct sockaddr_in6);
2497 sfamily = AF_INET6;
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002498 cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr,
2499 ntohs(sport));
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002500 } else {
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002501 struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr;
2502
2503 sport = ipv4->sin_port;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002504 slen = sizeof(struct sockaddr_in);
2505 sfamily = AF_INET;
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002506 cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr,
2507 ntohs(sport));
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002510 if (socket == NULL) {
Rob Landleyf1d0c992011-01-22 15:44:05 -06002511 rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
2512 IPPROTO_TCP, &socket, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 if (rc < 0) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002514 cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002515 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002518
2519 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesf96637b2013-05-04 22:12:25 -05002520 cifs_dbg(FYI, "Socket created\n");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002521 server->ssocket = socket;
2522 socket->sk->sk_allocation = GFP_NOFS;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002523 if (sfamily == AF_INET6)
2524 cifs_reclassify_socket6(socket);
2525 else
2526 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 }
2528
Ben Greear3eb9a882010-09-01 17:06:02 -07002529 rc = bind_socket(server);
2530 if (rc < 0)
2531 return rc;
2532
Jeff Laytond5c56052008-12-01 18:42:33 -05002533 /*
2534 * Eventually check for other socket options to change from
2535 * the default. sock_setsockopt not used because it expects
2536 * user space buffer
2537 */
2538 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002539 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002540
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002541 /* make the bufsizes depend on wsize/rsize and max requests */
2542 if (server->noautotune) {
2543 if (socket->sk->sk_sndbuf < (200 * 1024))
2544 socket->sk->sk_sndbuf = 200 * 1024;
2545 if (socket->sk->sk_rcvbuf < (140 * 1024))
2546 socket->sk->sk_rcvbuf = 140 * 1024;
2547 }
2548
Christoph Hellwig12abc5e2020-05-28 07:12:19 +02002549 if (server->tcp_nodelay)
2550 tcp_sock_set_nodelay(socket->sk);
Steve French6a5fa2362010-01-01 01:28:43 +00002551
Joe Perchesf96637b2013-05-04 22:12:25 -05002552 cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n",
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002553 socket->sk->sk_sndbuf,
2554 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
2555
Paulo Alcantara (SUSE)8eecd1c2019-07-16 19:04:50 -03002556 rc = socket->ops->connect(socket, saddr, slen,
2557 server->noblockcnt ? O_NONBLOCK : 0);
Paulo Alcantara (SUSE)d532cc72019-10-10 12:31:58 -03002558 /*
2559 * When mounting SMB root file systems, we do not want to block in
2560 * connect. Otherwise bail out and then let cifs_reconnect() perform
2561 * reconnect failover - if possible.
2562 */
2563 if (server->noblockcnt && rc == -EINPROGRESS)
Paulo Alcantara (SUSE)8eecd1c2019-07-16 19:04:50 -03002564 rc = 0;
Jeff Laytonee1b3ea2011-06-21 07:18:26 -04002565 if (rc < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002566 cifs_dbg(FYI, "Error %d connecting to server\n", rc);
Jeff Laytonee1b3ea2011-06-21 07:18:26 -04002567 sock_release(socket);
2568 server->ssocket = NULL;
2569 return rc;
2570 }
2571
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002572 if (sport == htons(RFC1001_PORT))
2573 rc = ip_rfc1001_connect(server);
Steve French50c2f752007-07-13 00:33:32 +00002574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 return rc;
2576}
2577
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002578static int
2579ip_connect(struct TCP_Server_Info *server)
2580{
Steve French6da97912011-03-13 18:55:55 +00002581 __be16 *sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002582 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
2583 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2584
2585 if (server->dstaddr.ss_family == AF_INET6)
2586 sport = &addr6->sin6_port;
2587 else
2588 sport = &addr->sin_port;
2589
2590 if (*sport == 0) {
2591 int rc;
2592
2593 /* try with 445 port at first */
2594 *sport = htons(CIFS_PORT);
2595
2596 rc = generic_ip_connect(server);
2597 if (rc >= 0)
2598 return rc;
2599
2600 /* if it failed, try with 139 port */
2601 *sport = htons(RFC1001_PORT);
2602 }
2603
2604 return generic_ip_connect(server);
2605}
2606
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002607void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002608 struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Steve French8af18972007-02-14 04:42:51 +00002609{
Steve Frenchbc044992020-12-11 19:48:26 -06002610 /*
2611 * If we are reconnecting then should we check to see if
Steve French8af18972007-02-14 04:42:51 +00002612 * any requested capabilities changed locally e.g. via
2613 * remount but we can not do much about it here
2614 * if they have (even if we could detect it by the following)
2615 * Perhaps we could add a backpointer to array of sb from tcon
2616 * or if we change to make all sb to same share the same
2617 * sb as NFS - then we only have one backpointer to sb.
2618 * What if we wanted to mount the server share twice once with
Steve Frenchbc044992020-12-11 19:48:26 -06002619 * and once without posixacls or posix paths?
2620 */
Steve French8af18972007-02-14 04:42:51 +00002621 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002622
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002623 if (ctx && ctx->no_linux_ext) {
Steve Frenchc18c8422007-07-18 23:21:09 +00002624 tcon->fsUnixInfo.Capability = 0;
2625 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -05002626 cifs_dbg(FYI, "Linux protocol extensions disabled\n");
Steve Frenchc18c8422007-07-18 23:21:09 +00002627 return;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002628 } else if (ctx)
Steve Frenchc18c8422007-07-18 23:21:09 +00002629 tcon->unix_ext = 1; /* Unix Extensions supported */
2630
Jiapeng Zhong16a78852021-01-14 18:02:23 +08002631 if (!tcon->unix_ext) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002632 cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
Steve Frenchc18c8422007-07-18 23:21:09 +00002633 return;
2634 }
Steve French50c2f752007-07-13 00:33:32 +00002635
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002636 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002637 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Joe Perchesf96637b2013-05-04 22:12:25 -05002638 cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
Steve Frenchbc044992020-12-11 19:48:26 -06002639 /*
2640 * check for reconnect case in which we do not
2641 * want to change the mount behavior if we can avoid it
2642 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002643 if (ctx == NULL) {
Steve Frenchbc044992020-12-11 19:48:26 -06002644 /*
2645 * turn off POSIX ACL and PATHNAMES if not set
2646 * originally at mount time
2647 */
Steve French8af18972007-02-14 04:42:51 +00002648 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2649 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002650 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2651 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002652 cifs_dbg(VFS, "POSIXPATH support change\n");
Steve French8af18972007-02-14 04:42:51 +00002653 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002654 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002655 cifs_dbg(VFS, "possible reconnect error\n");
2656 cifs_dbg(VFS, "server disabled POSIX path support\n");
Igor Mammedov11b6d642008-02-15 19:06:04 +00002657 }
Steve French8af18972007-02-14 04:42:51 +00002658 }
Steve French50c2f752007-07-13 00:33:32 +00002659
Steve French6848b732011-05-26 18:38:54 +00002660 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002661 cifs_dbg(VFS, "per-share encryption not supported yet\n");
Steve French6848b732011-05-26 18:38:54 +00002662
Steve French8af18972007-02-14 04:42:51 +00002663 cap &= CIFS_UNIX_CAP_MASK;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002664 if (ctx && ctx->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002665 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002666 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002667 cifs_dbg(FYI, "negotiated posix acl support\n");
Al Viro2c6292a2011-06-17 09:05:48 -04002668 if (cifs_sb)
2669 cifs_sb->mnt_cifs_flags |=
2670 CIFS_MOUNT_POSIXACL;
Steve French8af18972007-02-14 04:42:51 +00002671 }
2672
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002673 if (ctx && ctx->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002674 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002675 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002676 cifs_dbg(FYI, "negotiate posix pathnames\n");
Al Viro2c6292a2011-06-17 09:05:48 -04002677 if (cifs_sb)
2678 cifs_sb->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002679 CIFS_MOUNT_POSIX_PATHS;
2680 }
Steve French50c2f752007-07-13 00:33:32 +00002681
Joe Perchesf96637b2013-05-04 22:12:25 -05002682 cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00002683#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002684 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002685 cifs_dbg(FYI, "FCNTL cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002686 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002687 cifs_dbg(FYI, "EXTATTR cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002688 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002689 cifs_dbg(FYI, "POSIX path cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002690 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002691 cifs_dbg(FYI, "XATTR cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002692 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002693 cifs_dbg(FYI, "POSIX ACL cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002694 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002695 cifs_dbg(FYI, "very large read cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002696 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002697 cifs_dbg(FYI, "very large write cap\n");
Steve French6848b732011-05-26 18:38:54 +00002698 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002699 cifs_dbg(FYI, "transport encryption cap\n");
Steve French6848b732011-05-26 18:38:54 +00002700 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002701 cifs_dbg(FYI, "mandatory transport encryption cap\n");
Steve French8af18972007-02-14 04:42:51 +00002702#endif /* CIFS_DEBUG2 */
2703 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002704 if (ctx == NULL)
Joe Perchesf96637b2013-05-04 22:12:25 -05002705 cifs_dbg(FYI, "resetting capabilities failed\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002706 else
Joe Perchesf96637b2013-05-04 22:12:25 -05002707 cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n");
Steve French5a44b312007-09-20 15:16:24 +00002708
Steve French8af18972007-02-14 04:42:51 +00002709 }
2710 }
2711}
2712
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002713int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002714{
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002715 struct smb3_fs_context *ctx = cifs_sb->ctx;
2716
Jeff Layton2de970f2010-10-06 19:51:12 -04002717 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
2718
Al Viro2ced6f62011-06-17 09:20:04 -04002719 spin_lock_init(&cifs_sb->tlink_tree_lock);
2720 cifs_sb->tlink_tree = RB_ROOT;
2721
Frank Sorensonf52aa792020-02-12 15:31:48 -06002722 cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n",
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002723 ctx->file_mode, ctx->dir_mode);
Steve French3b795212008-11-13 19:45:32 +00002724
Ronnie Sahlberg387ec582020-12-14 16:40:20 +10002725 /* this is needed for ASCII cp to Unicode converts */
2726 if (ctx->iocharset == NULL) {
2727 /* load_nls_default cannot return null */
2728 cifs_sb->local_nls = load_nls_default();
2729 } else {
2730 cifs_sb->local_nls = load_nls(ctx->iocharset);
2731 if (cifs_sb->local_nls == NULL) {
2732 cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n",
2733 ctx->iocharset);
2734 return -ELIBACC;
2735 }
2736 }
2737 ctx->local_nls = cifs_sb->local_nls;
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05302738
Ronnie Sahlberg2d39f502020-12-14 16:40:25 +10002739 smb3_update_mnt_flags(cifs_sb);
2740
2741 if (ctx->direct_io)
Joe Perchesf96637b2013-05-04 22:12:25 -05002742 cifs_dbg(FYI, "mounting share using direct i/o\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002743 if (ctx->cache_ro) {
Steve French83bbfa72019-08-27 23:58:54 -05002744 cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
2745 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002746 } else if (ctx->cache_rw) {
Steve French41e033f2019-08-30 02:12:41 -05002747 cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
2748 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
2749 CIFS_MOUNT_RW_CACHE);
Steve French83bbfa72019-08-27 23:58:54 -05002750 }
Steve French3b795212008-11-13 19:45:32 +00002751
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002752 if ((ctx->cifs_acl) && (ctx->dynperm))
Joe Perchesf96637b2013-05-04 22:12:25 -05002753 cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n");
Sachin Prabhu4214ebf2016-07-29 22:38:19 +01002754
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002755 if (ctx->prepath) {
2756 cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL);
Sachin Prabhu4214ebf2016-07-29 22:38:19 +01002757 if (cifs_sb->prepath == NULL)
2758 return -ENOMEM;
2759 }
2760
2761 return 0;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002762}
2763
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002764/* Release all succeed connections */
2765static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
2766 unsigned int xid,
2767 struct TCP_Server_Info *server,
2768 struct cifs_ses *ses, struct cifs_tcon *tcon)
2769{
2770 int rc = 0;
2771
2772 if (tcon)
2773 cifs_put_tcon(tcon);
2774 else if (ses)
2775 cifs_put_smb_ses(ses);
2776 else if (server)
2777 cifs_put_tcp_session(server, 0);
2778 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
2779 free_xid(xid);
2780}
2781
2782/* Get connections for tcp, ses and tcon */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002783static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002784 unsigned int *xid,
2785 struct TCP_Server_Info **nserver,
2786 struct cifs_ses **nses, struct cifs_tcon **ntcon)
2787{
2788 int rc = 0;
2789 struct TCP_Server_Info *server;
2790 struct cifs_ses *ses;
2791 struct cifs_tcon *tcon;
2792
2793 *nserver = NULL;
2794 *nses = NULL;
2795 *ntcon = NULL;
2796
2797 *xid = get_xid();
2798
2799 /* get a reference to a tcp session */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002800 server = cifs_get_tcp_session(ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002801 if (IS_ERR(server)) {
2802 rc = PTR_ERR(server);
2803 return rc;
2804 }
2805
2806 *nserver = server;
2807
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002808 if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002809 server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
2810 else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002811 server->max_credits = ctx->max_credits;
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002812
2813 /* get a reference to a SMB session */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002814 ses = cifs_get_smb_ses(server, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002815 if (IS_ERR(ses)) {
2816 rc = PTR_ERR(ses);
2817 return rc;
2818 }
2819
2820 *nses = ses;
2821
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002822 if ((ctx->persistent == true) && (!(ses->server->capabilities &
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002823 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002824 cifs_server_dbg(VFS, "persistent handles not supported by server\n");
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002825 return -EOPNOTSUPP;
2826 }
2827
2828 /* search for existing tcon to this server share */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002829 tcon = cifs_get_tcon(ses, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002830 if (IS_ERR(tcon)) {
2831 rc = PTR_ERR(tcon);
2832 return rc;
2833 }
2834
2835 *ntcon = tcon;
2836
2837 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
2838 if (tcon->posix_extensions)
2839 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
2840
2841 /* tell server which Unix caps we support */
2842 if (cap_unix(tcon->ses)) {
2843 /*
2844 * reset of caps checks mount to see if unix extensions disabled
2845 * for just this mount.
2846 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002847 reset_cifs_unix_caps(*xid, tcon, cifs_sb, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002848 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
2849 (le64_to_cpu(tcon->fsUnixInfo.Capability) &
2850 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
2851 return -EACCES;
2852 } else
2853 tcon->unix_ext = 0; /* server does not support them */
2854
2855 /* do not care if a following call succeed - informational */
Steve French1981eba2019-08-29 22:33:38 -05002856 if (!tcon->pipe && server->ops->qfs_tcon) {
Amir Goldstein0f060932020-02-03 21:46:43 +02002857 server->ops->qfs_tcon(*xid, tcon, cifs_sb);
Steve French1981eba2019-08-29 22:33:38 -05002858 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
2859 if (tcon->fsDevInfo.DeviceCharacteristics &
Steve French52870d52019-10-01 21:25:46 -05002860 cpu_to_le32(FILE_READ_ONLY_DEVICE))
Steve French1981eba2019-08-29 22:33:38 -05002861 cifs_dbg(VFS, "mounted to read only share\n");
Steve French41e033f2019-08-30 02:12:41 -05002862 else if ((cifs_sb->mnt_cifs_flags &
2863 CIFS_MOUNT_RW_CACHE) == 0)
Steve French1981eba2019-08-29 22:33:38 -05002864 cifs_dbg(VFS, "read only mount of RW share\n");
Steve French41e033f2019-08-30 02:12:41 -05002865 /* no need to log a RW mount of a typical RW share */
Steve French1981eba2019-08-29 22:33:38 -05002866 }
2867 }
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002868
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002869 /*
2870 * Clamp the rsize/wsize mount arguments if they are too big for the server
Steve French0c2b5f72020-12-15 13:28:50 -06002871 * and set the rsize/wsize to the negotiated values if not passed in by
2872 * the user on mount
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002873 */
Steve French0c2b5f72020-12-15 13:28:50 -06002874 if ((cifs_sb->ctx->wsize == 0) ||
2875 (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx)))
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002876 cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx);
Steve French0c2b5f72020-12-15 13:28:50 -06002877 if ((cifs_sb->ctx->rsize == 0) ||
2878 (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002879 cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002880
2881 return 0;
2882}
2883
2884static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
2885 struct cifs_tcon *tcon)
2886{
2887 struct tcon_link *tlink;
2888
2889 /* hang the tcon off of the superblock */
2890 tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
2891 if (tlink == NULL)
2892 return -ENOMEM;
2893
2894 tlink->tl_uid = ses->linux_uid;
2895 tlink->tl_tcon = tcon;
2896 tlink->tl_time = jiffies;
2897 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2898 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2899
2900 cifs_sb->master_tlink = tlink;
2901 spin_lock(&cifs_sb->tlink_tree_lock);
2902 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
2903 spin_unlock(&cifs_sb->tlink_tree_lock);
2904
2905 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
2906 TLINK_IDLE_EXPIRE);
2907 return 0;
2908}
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04002909
Steve French2d6d5892009-04-09 00:36:44 +00002910#ifdef CONFIG_CIFS_DFS_UPCALL
Steve French6d3ea7e2012-11-28 22:34:41 -06002911/*
2912 * cifs_build_path_to_root returns full path to root when we do not have an
2913 * exiting connection (tcon)
2914 */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002915static char *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002916build_unc_path_to_root(const struct smb3_fs_context *ctx,
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02002917 const struct cifs_sb_info *cifs_sb, bool useppath)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002918{
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002919 char *full_path, *pos;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002920 unsigned int pplen = useppath && ctx->prepath ?
2921 strlen(ctx->prepath) + 1 : 0;
2922 unsigned int unc_len = strnlen(ctx->UNC, MAX_TREE_SIZE + 1);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002923
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002924 if (unc_len > MAX_TREE_SIZE)
2925 return ERR_PTR(-EINVAL);
2926
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002927 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002928 if (full_path == NULL)
2929 return ERR_PTR(-ENOMEM);
2930
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002931 memcpy(full_path, ctx->UNC, unc_len);
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002932 pos = full_path + unc_len;
2933
2934 if (pplen) {
Jeff Layton1fc29ba2013-05-31 10:00:18 -04002935 *pos = CIFS_DIR_SEP(cifs_sb);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002936 memcpy(pos + 1, ctx->prepath, pplen);
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002937 pos += pplen;
2938 }
2939
2940 *pos = '\0'; /* add trailing null */
Steve Frenchf87d39d2011-05-27 03:50:55 +00002941 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
Joe Perchesf96637b2013-05-04 22:12:25 -05002942 cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002943 return full_path;
2944}
Sean Finneydd613942011-04-11 13:19:30 +00002945
Paulo Alcantara1c780222018-11-14 16:24:03 -02002946/**
2947 * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb
2948 *
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10002949 * If a referral is found, cifs_sb->ctx->mount_options will be (re-)allocated
Sean Finney046462a2011-04-11 13:19:33 +00002950 * to a string containing updated options for the submount. Otherwise it
2951 * will be left untouched.
Sean Finneydd613942011-04-11 13:19:30 +00002952 *
2953 * Returns the rc from get_dfs_path to the caller, which can be used to
2954 * determine whether there were referrals.
2955 */
2956static int
Pavel Shilovskyb669f332012-05-27 20:21:53 +04002957expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002958 struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03002959 char *ref_path)
Sean Finneydd613942011-04-11 13:19:30 +00002960{
2961 int rc;
Paulo Alcantara1c780222018-11-14 16:24:03 -02002962 struct dfs_info3_param referral = {0};
Paulo Alcantara7efd0812020-07-21 09:36:44 -03002963 char *full_path = NULL, *mdata = NULL;
Sean Finneydd613942011-04-11 13:19:30 +00002964
Aurelien Aptel83930722018-09-20 18:10:25 -07002965 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
2966 return -EREMOTE;
2967
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002968 full_path = build_unc_path_to_root(ctx, cifs_sb, true);
Sean Finneydd613942011-04-11 13:19:30 +00002969 if (IS_ERR(full_path))
2970 return PTR_ERR(full_path);
2971
Paulo Alcantara1c780222018-11-14 16:24:03 -02002972 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
2973 ref_path, &referral, NULL);
2974 if (!rc) {
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10002975 mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
Ronnie Sahlberg4deb0752020-12-10 00:08:43 -06002976 full_path + 1, &referral);
Paulo Alcantara1c780222018-11-14 16:24:03 -02002977 free_dfs_info_param(&referral);
Sean Finney046462a2011-04-11 13:19:33 +00002978
Sean Finneydd613942011-04-11 13:19:30 +00002979 if (IS_ERR(mdata)) {
2980 rc = PTR_ERR(mdata);
2981 mdata = NULL;
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04002982 } else {
Ronnie Sahlbergc741cba2020-12-14 16:40:16 +10002983 smb3_cleanup_fs_context_contents(ctx);
Ronnie Sahlberg24e0a1e2020-12-10 00:06:02 -06002984 rc = cifs_setup_volume_info(ctx);
Sean Finneydd613942011-04-11 13:19:30 +00002985 }
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10002986 kfree(cifs_sb->ctx->mount_options);
2987 cifs_sb->ctx->mount_options = mdata;
Sean Finneydd613942011-04-11 13:19:30 +00002988 }
2989 kfree(full_path);
2990 return rc;
2991}
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02002992
2993static inline int get_next_dfs_tgt(const char *path,
2994 struct dfs_cache_tgt_list *tgt_list,
2995 struct dfs_cache_tgt_iterator **tgt_it)
2996{
2997 if (!*tgt_it)
2998 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
2999 else
3000 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
3001 return !*tgt_it ? -EHOSTDOWN : 0;
3002}
3003
3004static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003005 struct smb3_fs_context *fake_ctx, struct smb3_fs_context *ctx)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003006{
3007 const char *tgt = dfs_cache_get_tgt_name(tgt_it);
3008 int len = strlen(tgt) + 2;
3009 char *new_unc;
3010
3011 new_unc = kmalloc(len, GFP_KERNEL);
3012 if (!new_unc)
3013 return -ENOMEM;
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +10003014 scnprintf(new_unc, len, "\\%s", tgt);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003015
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003016 kfree(ctx->UNC);
3017 ctx->UNC = new_unc;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003018
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003019 if (fake_ctx->prepath) {
3020 kfree(ctx->prepath);
3021 ctx->prepath = fake_ctx->prepath;
3022 fake_ctx->prepath = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003023 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003024 memcpy(&ctx->dstaddr, &fake_ctx->dstaddr, sizeof(ctx->dstaddr));
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003025
3026 return 0;
3027}
3028
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003029static int setup_dfs_tgt_conn(const char *path, const char *full_path,
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003030 const struct dfs_cache_tgt_iterator *tgt_it,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003031 struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
3032 unsigned int *xid, struct TCP_Server_Info **server,
3033 struct cifs_ses **ses, struct cifs_tcon **tcon)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003034{
3035 int rc;
3036 struct dfs_info3_param ref = {0};
Ronnie Sahlberg4deb0752020-12-10 00:08:43 -06003037 char *mdata = NULL;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003038 struct smb3_fs_context fake_ctx = {NULL};
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003039
3040 cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
3041
3042 rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
3043 if (rc)
3044 return rc;
3045
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003046 mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
3047 full_path + 1, &ref);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003048 free_dfs_info_param(&ref);
3049
3050 if (IS_ERR(mdata)) {
3051 rc = PTR_ERR(mdata);
3052 mdata = NULL;
Ronnie Sahlberg24e0a1e2020-12-10 00:06:02 -06003053 } else
3054 rc = cifs_setup_volume_info(&fake_ctx);
3055
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003056 kfree(mdata);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003057
3058 if (!rc) {
3059 /*
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003060 * We use a 'fake_ctx' here because we need pass it down to the
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003061 * mount_{get,put} functions to test connection against new DFS
3062 * targets.
3063 */
3064 mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003065 rc = mount_get_conns(&fake_ctx, cifs_sb, xid, server, ses,
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003066 tcon);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003067 if (!rc || (*server && *ses)) {
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003068 /*
3069 * We were able to connect to new target server.
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003070 * Update current context with new target server.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003071 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003072 rc = update_vol_info(tgt_it, &fake_ctx, ctx);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003073 }
3074 }
Ronnie Sahlbergc741cba2020-12-14 16:40:16 +10003075 smb3_cleanup_fs_context_contents(&fake_ctx);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003076 return rc;
3077}
3078
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003079static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003080 struct smb3_fs_context *ctx, struct cifs_ses *root_ses,
3081 unsigned int *xid, struct TCP_Server_Info **server,
3082 struct cifs_ses **ses, struct cifs_tcon **tcon)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003083{
3084 int rc;
3085 struct dfs_cache_tgt_list tgt_list;
3086 struct dfs_cache_tgt_iterator *tgt_it = NULL;
3087
3088 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
3089 return -EOPNOTSUPP;
3090
3091 rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
3092 if (rc)
3093 return rc;
3094
3095 for (;;) {
3096 /* Get next DFS target server - if any */
3097 rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
3098 if (rc)
3099 break;
3100 /* Connect to next DFS target */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003101 rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, ctx, xid, server, ses,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003102 tcon);
3103 if (!rc || (*server && *ses))
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003104 break;
3105 }
3106 if (!rc) {
3107 /*
3108 * Update DFS target hint in DFS referral cache with the target
3109 * server we successfully reconnected to.
3110 */
3111 rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
3112 cifs_sb->local_nls,
3113 cifs_remap(cifs_sb), path,
3114 tgt_it);
3115 }
3116 dfs_cache_free_tgts(&tgt_list);
3117 return rc;
3118}
Steve French2d6d5892009-04-09 00:36:44 +00003119#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003120
Ronnie Sahlberg24e0a1e2020-12-10 00:06:02 -06003121/* TODO: all callers to this are broken. We are not parsing mount_options here
3122 * we should pass a clone of the original context?
3123 */
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03003124int
Ronnie Sahlberg24e0a1e2020-12-10 00:06:02 -06003125cifs_setup_volume_info(struct smb3_fs_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126{
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003127 int rc = 0;
Sean Finneydd613942011-04-11 13:19:30 +00003128
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003129 if (ctx->nullauth) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003130 cifs_dbg(FYI, "Anonymous login\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003131 kfree(ctx->username);
3132 ctx->username = NULL;
3133 } else if (ctx->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 /* BB fixme parse for domain name here */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003135 cifs_dbg(FYI, "Username: %s\n", ctx->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003137 cifs_dbg(VFS, "No username specified\n");
Steve French50c2f752007-07-13 00:33:32 +00003138 /* In userspace mount helper we can get user name from alternate
3139 locations such as env variables and files on disk */
Jeff Layton04db79b2011-07-06 08:10:38 -04003140 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 }
3142
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003143 return rc;
Jeff Layton04db79b2011-07-06 08:10:38 -04003144}
3145
Aurelien Aptela6b50582016-05-25 19:59:09 +02003146static int
3147cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
3148 unsigned int xid,
3149 struct cifs_tcon *tcon,
3150 struct cifs_sb_info *cifs_sb,
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003151 char *full_path,
3152 int added_treename)
Aurelien Aptela6b50582016-05-25 19:59:09 +02003153{
3154 int rc;
3155 char *s;
3156 char sep, tmp;
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003157 int skip = added_treename ? 1 : 0;
Aurelien Aptela6b50582016-05-25 19:59:09 +02003158
3159 sep = CIFS_DIR_SEP(cifs_sb);
3160 s = full_path;
3161
3162 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
3163 while (rc == 0) {
3164 /* skip separators */
3165 while (*s == sep)
3166 s++;
3167 if (!*s)
3168 break;
3169 /* next separator */
3170 while (*s && *s != sep)
3171 s++;
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003172 /*
3173 * if the treename is added, we then have to skip the first
3174 * part within the separators
3175 */
3176 if (skip) {
3177 skip = 0;
3178 continue;
3179 }
Aurelien Aptela6b50582016-05-25 19:59:09 +02003180 /*
3181 * temporarily null-terminate the path at the end of
3182 * the current component
3183 */
3184 tmp = *s;
3185 *s = 0;
3186 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3187 full_path);
3188 *s = tmp;
3189 }
3190 return rc;
3191}
3192
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003193/*
3194 * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
3195 * otherwise 0.
3196 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003197static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003198 const unsigned int xid,
3199 struct TCP_Server_Info *server,
3200 struct cifs_tcon *tcon)
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003201{
Jeff Layton1daaae82012-03-21 06:30:40 -04003202 int rc;
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003203 char *full_path;
3204
3205 if (!server->ops->is_path_accessible)
3206 return -EOPNOTSUPP;
3207
3208 /*
3209 * cifs_build_path_to_root works only when we have a valid tcon
3210 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003211 full_path = cifs_build_path_to_root(ctx, cifs_sb, tcon,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003212 tcon->Flags & SMB_SHARE_IS_IN_DFS);
3213 if (full_path == NULL)
3214 return -ENOMEM;
3215
3216 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
3217
3218 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3219 full_path);
3220 if (rc != 0 && rc != -EREMOTE) {
3221 kfree(full_path);
3222 return rc;
3223 }
3224
3225 if (rc != -EREMOTE) {
3226 rc = cifs_are_all_path_components_accessible(server, xid, tcon,
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003227 cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003228 if (rc != 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003229 cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003230 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
3231 rc = 0;
3232 }
3233 }
3234
3235 kfree(full_path);
3236 return rc;
3237}
3238
3239#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003240static void set_root_ses(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
3241 struct cifs_ses **root_ses)
Paulo Alcantara (SUSE)5bb30a42019-11-22 12:30:56 -03003242{
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003243 if (ses) {
3244 spin_lock(&cifs_tcp_ses_lock);
3245 ses->ses_count++;
Aurelien Aptel59463eb2020-12-03 19:46:08 +01003246 if (ses->tcon_ipc)
3247 ses->tcon_ipc->remap = cifs_remap(cifs_sb);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003248 spin_unlock(&cifs_tcp_ses_lock);
3249 }
3250 *root_ses = ses;
3251}
3252
3253static void put_root_ses(struct cifs_ses *ses)
3254{
3255 if (ses)
3256 cifs_put_smb_ses(ses);
3257}
3258
3259/* Check if a path component is remote and then update @dfs_path accordingly */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003260static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003261 const unsigned int xid, struct TCP_Server_Info *server,
3262 struct cifs_tcon *tcon, char **dfs_path)
3263{
3264 char *path, *s;
3265 char sep = CIFS_DIR_SEP(cifs_sb), tmp;
3266 char *npath;
3267 int rc = 0;
3268 int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS;
3269 int skip = added_treename;
3270
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003271 path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003272 if (!path)
3273 return -ENOMEM;
3274
3275 /*
3276 * Walk through the path components in @path and check if they're accessible. In case any of
3277 * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path
3278 * (NOT including the remaining components).
3279 */
3280 s = path;
3281 do {
3282 /* skip separators */
3283 while (*s && *s == sep)
3284 s++;
3285 if (!*s)
3286 break;
3287 /* next separator */
3288 while (*s && *s != sep)
3289 s++;
3290 /*
3291 * if the treename is added, we then have to skip the first
3292 * part within the separators
3293 */
3294 if (skip) {
3295 skip = 0;
3296 continue;
3297 }
3298 tmp = *s;
3299 *s = 0;
3300 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path);
3301 if (rc && rc == -EREMOTE) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003302 struct smb3_fs_context v = {NULL};
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003303 /* if @path contains a tree name, skip it in the prefix path */
3304 if (added_treename) {
Ronnie Sahlberg66e7b092020-11-05 13:58:14 +10003305 rc = smb3_parse_devname(path, &v);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003306 if (rc)
3307 break;
3308 rc = -EREMOTE;
3309 npath = build_unc_path_to_root(&v, cifs_sb, true);
Ronnie Sahlbergc741cba2020-12-14 16:40:16 +10003310 smb3_cleanup_fs_context_contents(&v);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003311 } else {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003312 v.UNC = ctx->UNC;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003313 v.prepath = path + 1;
3314 npath = build_unc_path_to_root(&v, cifs_sb, true);
3315 }
3316 if (IS_ERR(npath)) {
3317 rc = PTR_ERR(npath);
3318 break;
3319 }
3320 kfree(*dfs_path);
3321 *dfs_path = npath;
3322 }
3323 *s = tmp;
3324 } while (rc == 0);
3325
3326 kfree(path);
3327 return rc;
Paulo Alcantara (SUSE)5bb30a42019-11-22 12:30:56 -03003328}
3329
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003330int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003331{
3332 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003333 unsigned int xid;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003334 struct TCP_Server_Info *server = NULL;
3335 struct cifs_ses *ses = NULL, *root_ses = NULL;
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003336 struct cifs_tcon *tcon = NULL;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003337 int count = 0;
3338 char *ref_path = NULL, *full_path = NULL;
3339 char *oldmnt = NULL;
3340 char *mntdata = NULL;
Al Virodd854462011-06-17 08:24:42 -04003341
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003342 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003343 /*
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003344 * Unconditionally try to get an DFS referral (even cached) to determine whether it is an
3345 * DFS mount.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003346 *
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003347 * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
3348 * to respond with PATH_NOT_COVERED to requests that include the prefix.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003349 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003350 if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003351 NULL)) {
3352 /* No DFS referral was returned. Looks like a regular share. */
3353 if (rc)
3354 goto error;
3355 /* Check if it is fully accessible and then mount it */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003356 rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003357 if (!rc)
3358 goto out;
3359 if (rc != -EREMOTE)
3360 goto error;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003361 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003362 /* Save mount options */
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003363 mntdata = kstrndup(cifs_sb->ctx->mount_options,
3364 strlen(cifs_sb->ctx->mount_options), GFP_KERNEL);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003365 if (!mntdata) {
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03003366 rc = -ENOMEM;
3367 goto error;
3368 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003369 /* Get path of DFS root */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003370 ref_path = build_unc_path_to_root(ctx, cifs_sb, false);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003371 if (IS_ERR(ref_path)) {
3372 rc = PTR_ERR(ref_path);
3373 ref_path = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003374 goto error;
3375 }
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003376
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003377 set_root_ses(cifs_sb, ses, &root_ses);
3378 do {
3379 /* Save full path of last DFS path we used to resolve final target server */
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003380 kfree(full_path);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003381 full_path = build_unc_path_to_root(ctx, cifs_sb, !!count);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003382 if (IS_ERR(full_path)) {
3383 rc = PTR_ERR(full_path);
Dan Carpenter20b135e2020-08-05 12:52:07 +03003384 full_path = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003385 break;
3386 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003387 /* Chase referral */
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003388 oldmnt = cifs_sb->ctx->mount_options;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003389 rc = expand_dfs_referral(xid, root_ses, ctx, cifs_sb, ref_path + 1);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003390 if (rc)
3391 break;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003392 /* Connect to new DFS target only if we were redirected */
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003393 if (oldmnt != cifs_sb->ctx->mount_options) {
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003394 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003395 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003396 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003397 if (rc && !server && !ses) {
3398 /* Failed to connect. Try to connect to other targets in the referral. */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003399 rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, ctx, root_ses, &xid,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003400 &server, &ses, &tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003401 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003402 if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses)
3403 break;
3404 if (!tcon)
3405 continue;
3406 /* Make sure that requests go through new root servers */
Paulo Alcantarae1837852020-08-27 11:20:19 -03003407 if (is_tcon_dfs(tcon)) {
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003408 put_root_ses(root_ses);
3409 set_root_ses(cifs_sb, ses, &root_ses);
3410 }
3411 /* Check for remaining path components and then continue chasing them (-EREMOTE) */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003412 rc = check_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003413 /* Prevent recursion on broken link referrals */
3414 if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
3415 rc = -ELOOP;
3416 } while (rc == -EREMOTE);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003417
Jeff Layton9d002df2010-10-06 19:51:11 -04003418 if (rc)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003419 goto error;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003420 put_root_ses(root_ses);
3421 root_ses = NULL;
3422 kfree(ref_path);
3423 ref_path = NULL;
3424 /*
3425 * Store DFS full path in both superblock and tree connect structures.
3426 *
3427 * For DFS root mounts, the prefix path (cifs_sb->prepath) is preserved during reconnect so
3428 * only the root path is set in cifs_sb->origin_fullpath and tcon->dfs_path. And for DFS
3429 * links, the prefix path is included in both and may be changed during reconnect. See
3430 * cifs_tree_connect().
3431 */
3432 cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003433 if (!cifs_sb->origin_fullpath) {
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003434 rc = -ENOMEM;
3435 goto error;
3436 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003437 spin_lock(&cifs_tcp_ses_lock);
3438 tcon->dfs_path = full_path;
3439 full_path = NULL;
3440 tcon->remap = cifs_remap(cifs_sb);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003441 spin_unlock(&cifs_tcp_ses_lock);
3442
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003443 /* Add original context for DFS cache to be used when refreshing referrals */
3444 rc = dfs_cache_add_vol(mntdata, ctx, cifs_sb->origin_fullpath);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003445 if (rc)
Paulo Alcantarae511d312018-11-14 17:16:44 -02003446 goto error;
Aurelien Aptel5fc7fcd2018-11-16 16:13:25 +01003447 /*
3448 * After reconnecting to a different server, unique ids won't
3449 * match anymore, so we disable serverino. This prevents
3450 * dentry revalidation to think the dentry are stale (ESTALE).
3451 */
3452 cifs_autodisable_serverino(cifs_sb);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -03003453 /*
3454 * Force the use of prefix path to support failover on DFS paths that
3455 * resolve to targets that have different prefix paths.
3456 */
3457 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
3458 kfree(cifs_sb->prepath);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003459 cifs_sb->prepath = ctx->prepath;
3460 ctx->prepath = NULL;
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -03003461
Jeff Layton70fe7dc2007-11-16 22:21:07 +00003462out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003463 free_xid(xid);
Ronnie Sahlberg387ec582020-12-14 16:40:20 +10003464 cifs_try_adding_channels(cifs_sb, ses);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003465 return mount_setup_tlink(cifs_sb, ses, tcon);
3466
3467error:
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003468 kfree(ref_path);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003469 kfree(full_path);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003470 kfree(mntdata);
3471 kfree(cifs_sb->origin_fullpath);
3472 put_root_ses(root_ses);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003473 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 return rc;
3475}
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003476#else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003477int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003478{
3479 int rc = 0;
3480 unsigned int xid;
3481 struct cifs_ses *ses;
3482 struct cifs_tcon *tcon;
3483 struct TCP_Server_Info *server;
3484
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003485 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003486 if (rc)
3487 goto error;
3488
3489 if (tcon) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003490 rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003491 if (rc == -EREMOTE)
3492 rc = -EOPNOTSUPP;
3493 if (rc)
3494 goto error;
3495 }
3496
3497 free_xid(xid);
3498
3499 return mount_setup_tlink(cifs_sb, ses, tcon);
3500
3501error:
3502 mount_put_conns(cifs_sb, xid, server, ses, tcon);
3503 return rc;
3504}
3505#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
Jeff Layton8d1bca32011-06-11 21:17:10 -04003507/*
Aurelien Aptelb327a712018-01-24 13:46:10 +01003508 * Issue a TREE_CONNECT request.
Jeff Layton8d1bca32011-06-11 21:17:10 -04003509 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04003511CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
Steve French96daf2b2011-05-27 04:34:02 +00003512 const char *tree, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 const struct nls_table *nls_codepage)
3514{
3515 struct smb_hdr *smb_buffer;
3516 struct smb_hdr *smb_buffer_response;
3517 TCONX_REQ *pSMB;
3518 TCONX_RSP *pSMBr;
3519 unsigned char *bcc_ptr;
3520 int rc = 0;
Jeff Layton690c5222011-01-20 13:36:51 -05003521 int length;
3522 __u16 bytes_left, count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
3524 if (ses == NULL)
3525 return -EIO;
3526
3527 smb_buffer = cifs_buf_get();
Steve Frenchca43e3b2009-09-01 17:20:50 +00003528 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 return -ENOMEM;
Steve Frenchca43e3b2009-09-01 17:20:50 +00003530
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 smb_buffer_response = smb_buffer;
3532
3533 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3534 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003535
Pavel Shilovsky88257362012-05-23 14:01:59 +04003536 smb_buffer->Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 smb_buffer->Uid = ses->Suid;
3538 pSMB = (TCONX_REQ *) smb_buffer;
3539 pSMBr = (TCONX_RSP *) smb_buffer_response;
3540
3541 pSMB->AndXCommand = 0xFF;
3542 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 bcc_ptr = &pSMB->Password[0];
Aurelien Aptelb327a712018-01-24 13:46:10 +01003544 if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) {
Steve Frencheeac8042006-01-13 21:34:58 -08003545 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003546 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003547 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003548 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003549 } else {
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003550 pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003551 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3552 specified as required (when that support is added to
3553 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003554 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003555 by Samba (not sure whether other servers allow
3556 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003557#ifdef CONFIG_CIFS_WEAK_PW_HASH
Jeff Layton04912d62010-04-24 07:57:45 -04003558 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
Jeff Layton3f618222013-06-12 19:52:14 -05003559 (ses->sectype == LANMAN))
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -05003560 calc_lanman_hash(tcon->password, ses->server->cryptkey,
Steve French96daf2b2011-05-27 04:34:02 +00003561 ses->server->sec_mode &
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003562 SECMODE_PW_ENCRYPT ? true : false,
3563 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003564 else
3565#endif /* CIFS_WEAK_PW_HASH */
Shirish Pargaonkaree2c9252011-01-27 09:58:04 -06003566 rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
Shirish Pargaonkar9ef59922011-10-20 13:21:59 -05003567 bcc_ptr, nls_codepage);
Steve Frenchf3a31a22015-03-26 19:23:20 -05003568 if (rc) {
3569 cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
3570 __func__, rc);
3571 cifs_buf_release(smb_buffer);
3572 return rc;
3573 }
Steve Frencheeac8042006-01-13 21:34:58 -08003574
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003575 bcc_ptr += CIFS_AUTH_RESP_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003576 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003577 /* must align unicode strings */
3578 *bcc_ptr = 0; /* null byte password */
3579 bcc_ptr++;
3580 }
Steve Frencheeac8042006-01-13 21:34:58 -08003581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Jeff Layton38d77c52013-05-26 07:01:00 -04003583 if (ses->server->sign)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3585
3586 if (ses->capabilities & CAP_STATUS32) {
3587 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3588 }
3589 if (ses->capabilities & CAP_DFS) {
3590 smb_buffer->Flags2 |= SMBFLG2_DFS;
3591 }
3592 if (ses->capabilities & CAP_UNICODE) {
3593 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3594 length =
Steve Frenchacbbb762012-01-18 22:32:33 -06003595 cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
Steve French50c2f752007-07-13 00:33:32 +00003596 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003597 (/* server len*/ + 256 /* share len */), nls_codepage);
3598 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 bcc_ptr += 2; /* skip trailing null */
3600 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 strcpy(bcc_ptr, tree);
3602 bcc_ptr += strlen(tree) + 1;
3603 }
3604 strcpy(bcc_ptr, "?????");
3605 bcc_ptr += strlen("?????");
3606 bcc_ptr += 1;
3607 count = bcc_ptr - &pSMB->Password[0];
Qinglang Miao1a0e7f72020-07-25 16:56:01 +08003608 be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 pSMB->ByteCount = cpu_to_le16(count);
3610
Steve French133672e2007-11-13 22:41:37 +00003611 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
Jeff Layton77499812011-01-11 07:24:23 -05003612 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 /* above now done in SendReceive */
Aurelien Aptelb327a712018-01-24 13:46:10 +01003615 if (rc == 0) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003616 bool is_unicode;
3617
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003619 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 tcon->tid = smb_buffer_response->Tid;
3621 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Layton690c5222011-01-20 13:36:51 -05003622 bytes_left = get_bcc(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003623 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003624 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3625 is_unicode = true;
3626 else
3627 is_unicode = false;
3628
Jeff Laytoncc20c032009-04-30 07:16:21 -04003629
Steve French50c2f752007-07-13 00:33:32 +00003630 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003631 if (length == 3) {
3632 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3633 (bcc_ptr[2] == 'C')) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003634 cifs_dbg(FYI, "IPC connection\n");
Aurelien Aptelb327a712018-01-24 13:46:10 +01003635 tcon->ipc = true;
3636 tcon->pipe = true;
Steve French7f8ed422007-09-28 22:28:55 +00003637 }
3638 } else if (length == 2) {
3639 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3640 /* the most common case */
Joe Perchesf96637b2013-05-04 22:12:25 -05003641 cifs_dbg(FYI, "disk share connection\n");
Steve French7f8ed422007-09-28 22:28:55 +00003642 }
3643 }
Steve French50c2f752007-07-13 00:33:32 +00003644 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003645 bytes_left -= (length + 1);
Zhao Hongjiang46b51d02013-06-24 01:57:47 -05003646 strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
Jeff Laytoncc20c032009-04-30 07:16:21 -04003647
3648 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003649 kfree(tcon->nativeFileSystem);
Steve Frenchacbbb762012-01-18 22:32:33 -06003650 tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003651 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003652 nls_codepage);
3653
Joe Perchesf96637b2013-05-04 22:12:25 -05003654 cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003655
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003656 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003657 (smb_buffer_response->WordCount == 7))
3658 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003659 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3660 else
3661 tcon->Flags = 0;
Joe Perchesf96637b2013-05-04 22:12:25 -05003662 cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 }
3664
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003665 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 return rc;
3667}
3668
Al Viro2e32cf52013-10-03 12:53:37 -04003669static void delayed_free(struct rcu_head *p)
3670{
Ronnie Sahlbergd17abdf72020-11-10 08:59:26 +10003671 struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu);
3672
3673 unload_nls(cifs_sb->local_nls);
Ronnie Sahlbergc741cba2020-12-14 16:40:16 +10003674 smb3_cleanup_fs_context(cifs_sb->ctx);
Ronnie Sahlbergd17abdf72020-11-10 08:59:26 +10003675 kfree(cifs_sb);
Al Viro2e32cf52013-10-03 12:53:37 -04003676}
3677
Al Viro2a9b9952011-06-17 09:27:16 -04003678void
3679cifs_umount(struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
Jeff Laytonb647c352010-10-28 11:16:44 -04003681 struct rb_root *root = &cifs_sb->tlink_tree;
3682 struct rb_node *node;
3683 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
Jeff Layton2de970f2010-10-06 19:51:12 -04003685 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3686
Jeff Laytonb647c352010-10-28 11:16:44 -04003687 spin_lock(&cifs_sb->tlink_tree_lock);
3688 while ((node = rb_first(root))) {
3689 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3690 cifs_get_tlink(tlink);
3691 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3692 rb_erase(node, root);
Steve French50c2f752007-07-13 00:33:32 +00003693
Jeff Laytonb647c352010-10-28 11:16:44 -04003694 spin_unlock(&cifs_sb->tlink_tree_lock);
3695 cifs_put_tlink(tlink);
3696 spin_lock(&cifs_sb->tlink_tree_lock);
3697 }
3698 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003699
Aurelien Aptela6b50582016-05-25 19:59:09 +02003700 kfree(cifs_sb->prepath);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003701#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantarae511d312018-11-14 17:16:44 -02003702 dfs_cache_del_vol(cifs_sb->origin_fullpath);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003703 kfree(cifs_sb->origin_fullpath);
3704#endif
Al Viro2e32cf52013-10-03 12:53:37 -04003705 call_rcu(&cifs_sb->rcu, delayed_free);
Steve French50c2f752007-07-13 00:33:32 +00003706}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003708int
3709cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710{
3711 int rc = 0;
Aurelien Aptelf6a6bf72019-09-20 06:22:14 +02003712 struct TCP_Server_Info *server = cifs_ses_server(ses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003714 if (!server->ops->need_neg || !server->ops->negotiate)
3715 return -ENOSYS;
3716
Jeff Layton198b5682010-04-24 07:57:48 -04003717 /* only send once per connect */
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003718 if (!server->ops->need_neg(server))
Jeff Layton198b5682010-04-24 07:57:48 -04003719 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003721 rc = server->ops->negotiate(xid, ses);
Jeff Layton198b5682010-04-24 07:57:48 -04003722 if (rc == 0) {
3723 spin_lock(&GlobalMid_Lock);
Jeff Layton7fdbaa12011-06-10 16:14:57 -04003724 if (server->tcpStatus == CifsNeedNegotiate)
Jeff Layton198b5682010-04-24 07:57:48 -04003725 server->tcpStatus = CifsGood;
3726 else
3727 rc = -EHOSTDOWN;
3728 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 }
Steve French26b994f2008-08-06 05:11:33 +00003730
Jeff Layton198b5682010-04-24 07:57:48 -04003731 return rc;
3732}
Steve French26b994f2008-08-06 05:11:33 +00003733
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003734int
3735cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
3736 struct nls_table *nls_info)
Jeff Layton198b5682010-04-24 07:57:48 -04003737{
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003738 int rc = -ENOSYS;
Aurelien Aptelf6a6bf72019-09-20 06:22:14 +02003739 struct TCP_Server_Info *server = cifs_ses_server(ses);
Jeff Layton198b5682010-04-24 07:57:48 -04003740
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02003741 if (!ses->binding) {
3742 ses->capabilities = server->capabilities;
YANG LIed6b1922021-01-11 17:15:28 +08003743 if (!linuxExtEnabled)
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02003744 ses->capabilities &= (~server->vals->cap_unix);
3745
3746 if (ses->auth_key.response) {
3747 cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
3748 ses->auth_key.response);
3749 kfree(ses->auth_key.response);
3750 ses->auth_key.response = NULL;
3751 ses->auth_key.len = 0;
3752 }
3753 }
Steve French20418ac2009-04-30 16:13:32 +00003754
Joe Perchesf96637b2013-05-04 22:12:25 -05003755 cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
Steve French96daf2b2011-05-27 04:34:02 +00003756 server->sec_mode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003757
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003758 if (server->ops->sess_setup)
3759 rc = server->ops->sess_setup(xid, ses, nls_info);
3760
Shirish Pargaonkard4e63bd2013-08-29 08:35:09 -05003761 if (rc)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10003762 cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003763
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 return rc;
3765}
3766
Jeff Layton8a8798a2012-01-17 16:09:15 -05003767static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003768cifs_set_vol_auth(struct smb3_fs_context *ctx, struct cifs_ses *ses)
Jeff Layton8a8798a2012-01-17 16:09:15 -05003769{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003770 ctx->sectype = ses->sectype;
Jeff Layton3f618222013-06-12 19:52:14 -05003771
3772 /* krb5 is special, since we don't need username or pw */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003773 if (ctx->sectype == Kerberos)
Jeff Layton8a8798a2012-01-17 16:09:15 -05003774 return 0;
Jeff Layton8a8798a2012-01-17 16:09:15 -05003775
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003776 return cifs_set_cifscreds(ctx, ses);
Jeff Layton8a8798a2012-01-17 16:09:15 -05003777}
3778
Steve French96daf2b2011-05-27 04:34:02 +00003779static struct cifs_tcon *
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003780cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
Jeff Layton9d002df2010-10-06 19:51:11 -04003781{
Jeff Layton8a8798a2012-01-17 16:09:15 -05003782 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00003783 struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
3784 struct cifs_ses *ses;
3785 struct cifs_tcon *tcon = NULL;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003786 struct smb3_fs_context *ctx;
Jeff Layton9d002df2010-10-06 19:51:11 -04003787
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003788 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
3789 if (ctx == NULL)
Dan Carpenter803ab972012-01-24 11:39:22 +03003790 return ERR_PTR(-ENOMEM);
Jeff Layton9d002df2010-10-06 19:51:11 -04003791
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003792 ctx->local_nls = cifs_sb->local_nls;
3793 ctx->linux_uid = fsuid;
3794 ctx->cred_uid = fsuid;
3795 ctx->UNC = master_tcon->treeName;
3796 ctx->retry = master_tcon->retry;
3797 ctx->nocase = master_tcon->nocase;
3798 ctx->nohandlecache = master_tcon->nohandlecache;
3799 ctx->local_lease = master_tcon->local_lease;
3800 ctx->no_lease = master_tcon->no_lease;
3801 ctx->resilient = master_tcon->use_resilient;
3802 ctx->persistent = master_tcon->use_persistent;
3803 ctx->handle_timeout = master_tcon->handle_timeout;
3804 ctx->no_linux_ext = !master_tcon->unix_ext;
3805 ctx->linux_ext = master_tcon->posix_extensions;
3806 ctx->sectype = master_tcon->ses->sectype;
3807 ctx->sign = master_tcon->ses->sign;
3808 ctx->seal = master_tcon->seal;
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06003809#ifdef CONFIG_CIFS_SWN_UPCALL
3810 ctx->witness = master_tcon->use_witness;
3811#endif
Jeff Layton9d002df2010-10-06 19:51:11 -04003812
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003813 rc = cifs_set_vol_auth(ctx, master_tcon->ses);
Jeff Layton8a8798a2012-01-17 16:09:15 -05003814 if (rc) {
3815 tcon = ERR_PTR(rc);
3816 goto out;
3817 }
Jeff Layton9d002df2010-10-06 19:51:11 -04003818
3819 /* get a reference for the same TCP session */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303820 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003821 ++master_tcon->ses->server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303822 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003823
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003824 ses = cifs_get_smb_ses(master_tcon->ses->server, ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003825 if (IS_ERR(ses)) {
Steve French96daf2b2011-05-27 04:34:02 +00003826 tcon = (struct cifs_tcon *)ses;
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07003827 cifs_put_tcp_session(master_tcon->ses->server, 0);
Jeff Layton9d002df2010-10-06 19:51:11 -04003828 goto out;
3829 }
3830
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003831 tcon = cifs_get_tcon(ses, ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003832 if (IS_ERR(tcon)) {
3833 cifs_put_smb_ses(ses);
3834 goto out;
3835 }
3836
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04003837 if (cap_unix(ses))
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003838 reset_cifs_unix_caps(0, tcon, NULL, ctx);
Steve Frenchb3266142018-05-20 23:41:10 -05003839
Jeff Layton9d002df2010-10-06 19:51:11 -04003840out:
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003841 kfree(ctx->username);
3842 kfree_sensitive(ctx->password);
3843 kfree(ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003844
3845 return tcon;
3846}
3847
Steve French96daf2b2011-05-27 04:34:02 +00003848struct cifs_tcon *
Jeff Layton9d002df2010-10-06 19:51:11 -04003849cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3850{
3851 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3852}
3853
Jeff Laytonb647c352010-10-28 11:16:44 -04003854/* find and return a tlink with given uid */
3855static struct tcon_link *
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003856tlink_rb_search(struct rb_root *root, kuid_t uid)
Jeff Laytonb647c352010-10-28 11:16:44 -04003857{
3858 struct rb_node *node = root->rb_node;
3859 struct tcon_link *tlink;
3860
3861 while (node) {
3862 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3863
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003864 if (uid_gt(tlink->tl_uid, uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003865 node = node->rb_left;
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003866 else if (uid_lt(tlink->tl_uid, uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003867 node = node->rb_right;
3868 else
3869 return tlink;
3870 }
3871 return NULL;
3872}
3873
3874/* insert a tcon_link into the tree */
3875static void
3876tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
3877{
3878 struct rb_node **new = &(root->rb_node), *parent = NULL;
3879 struct tcon_link *tlink;
3880
3881 while (*new) {
3882 tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
3883 parent = *new;
3884
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003885 if (uid_gt(tlink->tl_uid, new_tlink->tl_uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003886 new = &((*new)->rb_left);
3887 else
3888 new = &((*new)->rb_right);
3889 }
3890
3891 rb_link_node(&new_tlink->tl_rbnode, parent, new);
3892 rb_insert_color(&new_tlink->tl_rbnode, root);
3893}
3894
Jeff Layton9d002df2010-10-06 19:51:11 -04003895/*
3896 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3897 * current task.
3898 *
3899 * If the superblock doesn't refer to a multiuser mount, then just return
3900 * the master tcon for the mount.
3901 *
Suresh Jayaraman6ef933a2010-11-03 10:53:49 +05303902 * First, search the rbtree for an existing tcon for this fsuid. If one
Jeff Layton9d002df2010-10-06 19:51:11 -04003903 * exists, then check to see if it's pending construction. If it is then wait
3904 * for construction to complete. Once it's no longer pending, check to see if
3905 * it failed and either return an error or retry construction, depending on
3906 * the timeout.
3907 *
3908 * If one doesn't exist then insert a new tcon_link struct into the tree and
3909 * try to construct a new one.
3910 */
3911struct tcon_link *
3912cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
3913{
3914 int ret;
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003915 kuid_t fsuid = current_fsuid();
Jeff Layton9d002df2010-10-06 19:51:11 -04003916 struct tcon_link *tlink, *newtlink;
3917
3918 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
3919 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3920
3921 spin_lock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04003922 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04003923 if (tlink)
3924 cifs_get_tlink(tlink);
3925 spin_unlock(&cifs_sb->tlink_tree_lock);
3926
3927 if (tlink == NULL) {
3928 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
3929 if (newtlink == NULL)
3930 return ERR_PTR(-ENOMEM);
Jeff Laytonb647c352010-10-28 11:16:44 -04003931 newtlink->tl_uid = fsuid;
Jeff Layton9d002df2010-10-06 19:51:11 -04003932 newtlink->tl_tcon = ERR_PTR(-EACCES);
3933 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
3934 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
3935 cifs_get_tlink(newtlink);
3936
Jeff Layton9d002df2010-10-06 19:51:11 -04003937 spin_lock(&cifs_sb->tlink_tree_lock);
3938 /* was one inserted after previous search? */
Jeff Laytonb647c352010-10-28 11:16:44 -04003939 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04003940 if (tlink) {
3941 cifs_get_tlink(tlink);
3942 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003943 kfree(newtlink);
3944 goto wait_for_construction;
3945 }
Jeff Layton9d002df2010-10-06 19:51:11 -04003946 tlink = newtlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04003947 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
3948 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003949 } else {
3950wait_for_construction:
3951 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
Jeff Layton9d002df2010-10-06 19:51:11 -04003952 TASK_INTERRUPTIBLE);
3953 if (ret) {
3954 cifs_put_tlink(tlink);
NeilBrown74316202014-07-07 15:16:04 +10003955 return ERR_PTR(-ERESTARTSYS);
Jeff Layton9d002df2010-10-06 19:51:11 -04003956 }
3957
3958 /* if it's good, return it */
3959 if (!IS_ERR(tlink->tl_tcon))
3960 return tlink;
3961
3962 /* return error if we tried this already recently */
3963 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
3964 cifs_put_tlink(tlink);
3965 return ERR_PTR(-EACCES);
3966 }
3967
3968 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
3969 goto wait_for_construction;
3970 }
3971
3972 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
3973 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
3974 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
3975
3976 if (IS_ERR(tlink->tl_tcon)) {
3977 cifs_put_tlink(tlink);
3978 return ERR_PTR(-EACCES);
3979 }
3980
3981 return tlink;
3982}
Jeff Layton2de970f2010-10-06 19:51:12 -04003983
3984/*
3985 * periodic workqueue job that scans tcon_tree for a superblock and closes
3986 * out tcons.
3987 */
3988static void
3989cifs_prune_tlinks(struct work_struct *work)
3990{
3991 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
3992 prune_tlinks.work);
Jeff Laytonb647c352010-10-28 11:16:44 -04003993 struct rb_root *root = &cifs_sb->tlink_tree;
Colin Ian King37e12f52018-01-17 09:52:39 +00003994 struct rb_node *node;
Jeff Laytonb647c352010-10-28 11:16:44 -04003995 struct rb_node *tmp;
3996 struct tcon_link *tlink;
Jeff Layton2de970f2010-10-06 19:51:12 -04003997
Jeff Laytonb647c352010-10-28 11:16:44 -04003998 /*
3999 * Because we drop the spinlock in the loop in order to put the tlink
4000 * it's not guarded against removal of links from the tree. The only
4001 * places that remove entries from the tree are this function and
4002 * umounts. Because this function is non-reentrant and is canceled
4003 * before umount can proceed, this is safe.
4004 */
4005 spin_lock(&cifs_sb->tlink_tree_lock);
4006 node = rb_first(root);
4007 while (node != NULL) {
4008 tmp = node;
4009 node = rb_next(tmp);
4010 tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
4011
4012 if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
4013 atomic_read(&tlink->tl_count) != 0 ||
4014 time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
4015 continue;
4016
4017 cifs_get_tlink(tlink);
4018 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4019 rb_erase(tmp, root);
4020
Jeff Layton2de970f2010-10-06 19:51:12 -04004021 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04004022 cifs_put_tlink(tlink);
4023 spin_lock(&cifs_sb->tlink_tree_lock);
4024 }
4025 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton2de970f2010-10-06 19:51:12 -04004026
Jeff Laytonda472fc2012-03-23 14:40:53 -04004027 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
Jeff Layton2de970f2010-10-06 19:51:12 -04004028 TLINK_IDLE_EXPIRE);
4029}
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004030
4031#ifdef CONFIG_CIFS_DFS_UPCALL
4032int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
4033{
4034 int rc;
4035 struct TCP_Server_Info *server = tcon->ses->server;
4036 const struct smb_version_operations *ops = server->ops;
4037 struct dfs_cache_tgt_list tl;
4038 struct dfs_cache_tgt_iterator *it = NULL;
4039 char *tree;
4040 const char *tcp_host;
4041 size_t tcp_host_len;
4042 const char *dfs_host;
4043 size_t dfs_host_len;
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004044 char *share = NULL, *prefix = NULL;
Paulo Alcantara11375a52020-07-21 09:36:43 -03004045 struct dfs_info3_param ref = {0};
4046 bool isroot;
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004047
4048 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
4049 if (!tree)
4050 return -ENOMEM;
4051
4052 if (!tcon->dfs_path) {
4053 if (tcon->ipc) {
4054 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
4055 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
4056 } else {
4057 rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
4058 }
4059 goto out;
4060 }
4061
Paulo Alcantara11375a52020-07-21 09:36:43 -03004062 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004063 if (rc)
4064 goto out;
Paulo Alcantara11375a52020-07-21 09:36:43 -03004065 isroot = ref.server_type == DFS_TYPE_ROOT;
4066 free_dfs_info_param(&ref);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004067
4068 extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
4069
4070 for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004071 bool target_match;
4072
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004073 kfree(share);
4074 kfree(prefix);
Colin Ian Kingc6a80e12020-07-31 18:13:42 +01004075 share = NULL;
4076 prefix = NULL;
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004077
4078 rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004079 if (rc) {
4080 cifs_dbg(VFS, "%s: failed to parse target share %d\n",
4081 __func__, rc);
4082 continue;
4083 }
4084
4085 extract_unc_hostname(share, &dfs_host, &dfs_host_len);
4086
4087 if (dfs_host_len != tcp_host_len
4088 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
4089 cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
4090 dfs_host, (int)tcp_host_len, tcp_host);
4091
4092 rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
4093 if (rc) {
4094 cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc);
4095 break;
4096 }
4097
4098 if (!target_match) {
4099 cifs_dbg(FYI, "%s: skipping target\n", __func__);
4100 continue;
4101 }
4102 }
4103
4104 if (tcon->ipc) {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004105 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004106 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
4107 } else {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004108 scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004109 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
Paulo Alcantara11375a52020-07-21 09:36:43 -03004110 /* Only handle prefix paths of DFS link targets */
4111 if (!rc && !isroot) {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004112 rc = update_super_prepath(tcon, prefix);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004113 break;
4114 }
4115 }
4116 if (rc == -EREMOTE)
4117 break;
4118 }
4119
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004120 kfree(share);
4121 kfree(prefix);
4122
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004123 if (!rc) {
4124 if (it)
4125 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
4126 else
4127 rc = -ENOENT;
4128 }
4129 dfs_cache_free_tgts(&tl);
4130out:
4131 kfree(tree);
4132 return rc;
4133}
4134#else
4135int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
4136{
4137 const struct smb_version_operations *ops = tcon->ses->server->ops;
4138
4139 return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
4140}
4141#endif