blob: 10011e99b34dc6412c8f0e3d15263547a870da93 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve Frenchd185cda2009-04-30 17:45:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Igor Mammedov5c2503a2009-04-21 19:31:05 +040036#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/uaccess.h>
38#include <asm/processor.h>
Jeff Layton50b64e32009-06-02 06:55:20 -040039#include <linux/inet.h>
Steve French0e2beda2009-01-30 21:24:41 +000040#include <net/ipv6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "cifspdu.h"
42#include "cifsglob.h"
43#include "cifsproto.h"
44#include "cifs_unicode.h"
45#include "cifs_debug.h"
46#include "cifs_fs_sb.h"
47#include "ntlmssp.h"
48#include "nterr.h"
49#include "rfc1002pdu.h"
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053050#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define CIFS_PORT 445
53#define RFC1001_PORT 139
54
Jeff Laytonc74093b2011-01-11 07:24:23 -050055/* SMB echo "timeout" -- FIXME: tunable? */
56#define SMB_ECHO_INTERVAL (60 * HZ)
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058extern mempool_t *cifs_req_poolp;
59
60struct smb_vol {
61 char *username;
62 char *password;
63 char *domainname;
64 char *UNC;
65 char *UNCip;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 char *iocharset; /* local code page for mapping to and from Unicode */
Jeff Layton1397f2e2011-01-07 11:30:28 -050067 char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
68 char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
Jeff Layton3e4b3e12010-07-19 18:00:17 -040069 uid_t cred_uid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 uid_t linux_uid;
71 gid_t linux_gid;
72 mode_t file_mode;
73 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000074 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000075 bool retry:1;
76 bool intr:1;
77 bool setuids:1;
78 bool override_uid:1;
79 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000080 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000081 bool noperm:1;
82 bool no_psx_acl:1; /* set if posix acl support should be disabled */
83 bool cifs_acl:1;
84 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
85 bool server_ino:1; /* use inode numbers from server ie UniqueId */
86 bool direct_io:1;
Pavel Shilovskyd39454f2011-01-24 14:16:35 -050087 bool strict_io:1; /* strict cache behavior */
Steve French95b1cb92008-05-15 16:44:38 +000088 bool remap:1; /* set to remap seven reserved chars in filenames */
89 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000090 bool no_linux_ext:1;
91 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000092 bool nullauth:1; /* attempt to authenticate with null user */
93 bool nocase:1; /* request case insensitive filenames */
94 bool nobrl:1; /* disable sending byte range locks to srv */
Steve French13a6e422008-12-02 17:24:33 +000095 bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
Steve French95b1cb92008-05-15 16:44:38 +000096 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000097 bool nodfs:1; /* Do not request DFS, even if available */
98 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000099 bool noblocksnd:1;
100 bool noautotune:1;
Steve Frenchbe652442009-02-23 15:21:59 +0000101 bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
Suresh Jayaramanfa1df752010-07-05 18:13:36 +0530102 bool fsc:1; /* enable fscache */
Stefan Metzmacher736a3322010-07-30 14:56:00 +0200103 bool mfsymlinks:1; /* use Minshall+French Symlinks */
Jeff Layton0eb8a132010-10-06 19:51:12 -0400104 bool multiuser:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 unsigned int rsize;
106 unsigned int wsize;
Steve French6a5fa2362010-01-01 01:28:43 +0000107 bool sockopt_tcp_nodelay:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 unsigned short int port;
Suresh Jayaraman6d20e842010-12-01 14:42:28 +0530109 unsigned long actimeo; /* attribute cache timeout (jiffies) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110 char *prepath;
Ben Greear3eb9a882010-09-01 17:06:02 -0700111 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
Jeff Laytona5fc4ce2010-04-24 07:57:42 -0400112 struct nls_table *local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
Jeff Layton2de970f2010-10-06 19:51:12 -0400115/* FIXME: should these be tunable? */
Jeff Layton9d002df2010-10-06 19:51:11 -0400116#define TLINK_ERROR_EXPIRE (1 * HZ)
Jeff Layton2de970f2010-10-06 19:51:12 -0400117#define TLINK_IDLE_EXPIRE (600 * HZ)
Jeff Layton9d002df2010-10-06 19:51:11 -0400118
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300119static int ip_connect(struct TCP_Server_Info *server);
120static int generic_ip_connect(struct TCP_Server_Info *server);
Jeff Laytonb647c352010-10-28 11:16:44 -0400121static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
Jeff Layton2de970f2010-10-06 19:51:12 -0400122static void cifs_prune_tlinks(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Jeff Laytond5c56052008-12-01 18:42:33 -0500124/*
125 * cifs tcp session reconnection
126 *
127 * mark tcp session as reconnecting so temporarily locked
128 * mark all smb sessions as reconnecting for tcp session
129 * reconnect tcp session
130 * wake up waiters on reconnection? - (not needed currently)
131 */
Steve French2cd646a2006-09-28 19:43:08 +0000132static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133cifs_reconnect(struct TCP_Server_Info *server)
134{
135 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500136 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct cifsSesInfo *ses;
138 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000139 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000142 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000143 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 next time through the loop */
145 spin_unlock(&GlobalMid_Lock);
146 return rc;
147 } else
148 server->tcpStatus = CifsNeedReconnect;
149 spin_unlock(&GlobalMid_Lock);
150 server->maxBuf = 0;
151
Joe Perchesb6b38f72010-04-21 03:50:45 +0000152 cFYI(1, "Reconnecting tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154 /* before reconnecting the tcp session, mark the smb session (uid)
155 and the tid bad so they are not used until reconnected */
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500156 cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530157 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500158 list_for_each(tmp, &server->smb_ses_list) {
159 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
160 ses->need_reconnect = true;
161 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500162 list_for_each(tmp2, &ses->tcon_list) {
163 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
164 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530167 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 /* do not want to be sending data on a socket we are freeing */
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500170 cFYI(1, "%s: tearing down socket", __func__);
Jeff Layton72ca5452008-12-01 07:09:36 -0500171 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000172 if (server->ssocket) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000173 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
174 server->ssocket->flags);
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800175 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000176 cFYI(1, "Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000177 server->ssocket->state,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000178 server->ssocket->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 sock_release(server->ssocket);
180 server->ssocket = NULL;
181 }
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -0500182 server->sequence_number = 0;
183 server->session_estab = false;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -0500184 kfree(server->session_key.response);
185 server->session_key.response = NULL;
186 server->session_key.len = 0;
Steve Frenchfda35942011-01-20 18:06:34 +0000187 server->lstrp = jiffies;
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500188 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500190 /* mark submitted MIDs for retry and issue callback */
191 cFYI(1, "%s: issuing mid callbacks", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 spin_lock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500193 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
194 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
195 if (mid_entry->midState == MID_REQUEST_SUBMITTED)
Steve Frenchad8b15f2008-08-08 21:10:16 +0000196 mid_entry->midState = MID_RETRY_NEEDED;
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500197 list_del_init(&mid_entry->qhead);
198 mid_entry->callback(mid_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
200 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Jeff Layton469ee612008-10-16 18:46:39 +0000202 while ((server->tcpStatus != CifsExiting) &&
203 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000204 try_to_freeze();
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300205
206 /* we should try only the port we connected to before */
207 rc = generic_ip_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000208 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000209 cFYI(1, "reconnect error %d", rc);
Steve French0cb766a2005-04-28 22:41:11 -0700210 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 } else {
212 atomic_inc(&tcpSesReconnectCount);
213 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000214 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 server->tcpStatus = CifsGood;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000216 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
218 }
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
221}
222
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000223/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700224 return codes:
225 0 not a transact2, or all data present
226 >0 transact2 with that much data missing
227 -EINVAL = invalid transact2
228
229 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000230static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700231{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 struct smb_t2_rsp *pSMBt;
Steve Frenche4eb2952005-04-28 22:41:09 -0700233 int remaining;
Jeff Layton26ec2542011-01-20 13:36:51 -0500234 __u16 total_data_size, data_in_this_rsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700235
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000236 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700237 return 0;
238
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000239 /* check for plausible wct, bcc and t2 data and parm sizes */
240 /* check for parm and data offset going beyond end of smb */
241 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000242 cFYI(1, "invalid transact2 word count");
Steve Frenche4eb2952005-04-28 22:41:09 -0700243 return -EINVAL;
244 }
245
246 pSMBt = (struct smb_t2_rsp *)pSMB;
247
Jeff Layton26ec2542011-01-20 13:36:51 -0500248 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
249 data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
Steve Frenche4eb2952005-04-28 22:41:09 -0700250
251 remaining = total_data_size - data_in_this_rsp;
252
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000253 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700254 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000255 else if (remaining < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000256 cFYI(1, "total data %d smaller than data in frame %d",
257 total_data_size, data_in_this_rsp);
Steve Frenche4eb2952005-04-28 22:41:09 -0700258 return -EINVAL;
259 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000260 cFYI(1, "missing %d bytes from transact2, check next response",
261 remaining);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000262 if (total_data_size > maxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000263 cERROR(1, "TotalDataSize %d is over maximum buffer %d",
264 total_data_size, maxBufSize);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000265 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700266 }
267 return remaining;
268 }
269}
270
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000271static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700272{
273 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
274 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 char *data_area_of_target;
276 char *data_area_of_buf2;
Jeff Layton26ec2542011-01-20 13:36:51 -0500277 int remaining;
278 __u16 byte_count, total_data_size, total_in_buf, total_in_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700279
Jeff Layton26ec2542011-01-20 13:36:51 -0500280 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
Steve Frenche4eb2952005-04-28 22:41:09 -0700281
Jeff Layton26ec2542011-01-20 13:36:51 -0500282 if (total_data_size !=
283 get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount))
Joe Perchesb6b38f72010-04-21 03:50:45 +0000284 cFYI(1, "total data size of primary and secondary t2 differ");
Steve Frenche4eb2952005-04-28 22:41:09 -0700285
Jeff Layton26ec2542011-01-20 13:36:51 -0500286 total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
Steve Frenche4eb2952005-04-28 22:41:09 -0700287
288 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000289
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000290 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700291 return -EINVAL;
292
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000293 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700294 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000295
Jeff Layton26ec2542011-01-20 13:36:51 -0500296 total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000297 if (remaining < total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000298 cFYI(1, "transact2 2nd response contains too much data");
Steve Frenche4eb2952005-04-28 22:41:09 -0700299 }
300
301 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000302 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Jeff Layton26ec2542011-01-20 13:36:51 -0500303 get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700304 /* validate target area */
305
Jeff Layton26ec2542011-01-20 13:36:51 -0500306 data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
307 get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700308
309 data_area_of_target += total_in_buf;
310
311 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000312 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700313 total_in_buf += total_in_buf2;
Jeff Layton26ec2542011-01-20 13:36:51 -0500314 put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
Jeff Layton690c5222011-01-20 13:36:51 -0500315 byte_count = get_bcc_le(pTargetSMB);
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 byte_count += total_in_buf2;
Jeff Layton690c5222011-01-20 13:36:51 -0500317 put_bcc_le(byte_count, pTargetSMB);
Steve Frenche4eb2952005-04-28 22:41:09 -0700318
Steve French70ca7342005-09-22 16:32:06 -0700319 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700320 byte_count += total_in_buf2;
321
322 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000323
Steve French70ca7342005-09-22 16:32:06 -0700324 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700325
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000326 if (remaining == total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000327 cFYI(1, "found the last secondary response");
Steve Frenche4eb2952005-04-28 22:41:09 -0700328 return 0; /* we are done */
329 } else /* more responses to go */
330 return 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700331}
332
Jeff Laytonc74093b2011-01-11 07:24:23 -0500333static void
334cifs_echo_request(struct work_struct *work)
335{
336 int rc;
337 struct TCP_Server_Info *server = container_of(work,
338 struct TCP_Server_Info, echo.work);
339
Jeff Layton247ec9b2011-02-04 17:09:50 -0500340 /*
341 * We cannot send an echo until the NEGOTIATE_PROTOCOL request is done.
342 * Also, no need to ping if we got a response recently
343 */
Steve French7e90d702011-02-08 23:52:32 +0000344 if ((server->tcpStatus != CifsGood) || (server->maxBuf == 0) ||
Jeff Layton247ec9b2011-02-04 17:09:50 -0500345 time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
Jeff Laytonc74093b2011-01-11 07:24:23 -0500346 goto requeue_echo;
347
348 rc = CIFSSMBEcho(server);
349 if (rc)
350 cFYI(1, "Unable to send echo request to server: %s",
351 server->hostname);
352
353requeue_echo:
354 queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
355}
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357static int
358cifs_demultiplex_thread(struct TCP_Server_Info *server)
359{
360 int length;
361 unsigned int pdu_length, total_read;
362 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700363 struct smb_hdr *bigbuf = NULL;
364 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 struct msghdr smb_msg;
366 struct kvec iov;
367 struct socket *csocket = server->ssocket;
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500368 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 struct task_struct *task_to_wake = NULL;
370 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700371 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000372 bool isLargeBuf = false;
373 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700374 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 current->flags |= PF_MEMALLOC;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000377 cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400378
379 length = atomic_inc_return(&tcpSesAllocCount);
380 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000381 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
382 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700384 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000385 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700386 if (try_to_freeze())
387 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700388 if (bigbuf == NULL) {
389 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000390 if (!bigbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000391 cERROR(1, "No memory for large SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 msleep(3000);
393 /* retry will check if exiting */
394 continue;
395 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000396 } else if (isLargeBuf) {
397 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000398 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700400
401 if (smallbuf == NULL) {
402 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000403 if (!smallbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000404 cERROR(1, "No memory for SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700405 msleep(1000);
406 /* retry will check if exiting */
407 continue;
408 }
409 /* beginning of smb buffer is cleared in our buf_get */
410 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000411 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700412
Steve French4b18f2a2008-04-29 00:06:05 +0000413 isLargeBuf = false;
414 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700415 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 iov.iov_base = smb_buffer;
417 iov.iov_len = 4;
418 smb_msg.msg_control = NULL;
419 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000420 pdu_length = 4; /* enough to get RFC1001 header */
Steve Frenchfda35942011-01-20 18:06:34 +0000421
Steve Frenchf01d5e12007-08-30 21:13:31 +0000422incomplete_rcv:
Steve Frenchfda35942011-01-20 18:06:34 +0000423 if (echo_retries > 0 &&
424 time_after(jiffies, server->lstrp +
425 (echo_retries * SMB_ECHO_INTERVAL))) {
426 cERROR(1, "Server %s has not responded in %d seconds. "
427 "Reconnecting...", server->hostname,
428 (echo_retries * SMB_ECHO_INTERVAL / HZ));
429 cifs_reconnect(server);
430 csocket = server->ssocket;
431 wake_up(&server->response_q);
432 continue;
433 }
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 length =
436 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000437 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Jeff Layton469ee612008-10-16 18:46:39 +0000439 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 break;
441 } else if (server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000442 cFYI(1, "Reconnect after server stopped responding");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 cifs_reconnect(server);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000444 cFYI(1, "call to reconnect done");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 csocket = server->ssocket;
446 continue;
Jeff Layton522bbe62010-09-03 12:00:49 -0400447 } else if (length == -ERESTARTSYS ||
448 length == -EAGAIN ||
449 length == -EINTR) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700450 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 allowing socket to clear and app threads to set
452 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000453 if (pdu_length < 4) {
454 iov.iov_base = (4 - pdu_length) +
455 (char *)smb_buffer;
456 iov.iov_len = pdu_length;
457 smb_msg.msg_control = NULL;
458 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000459 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000460 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000461 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000463 cFYI(1, "Reconnect after unexpected peek error %d",
464 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 cifs_reconnect(server);
466 csocket = server->ssocket;
467 wake_up(&server->response_q);
468 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000469 } else if (length < pdu_length) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000470 cFYI(1, "requested %d bytes but only got %d bytes",
471 pdu_length, length);
Steve Frenchf01d5e12007-08-30 21:13:31 +0000472 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000473 msleep(1);
474 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
Steve French67010fb2005-04-28 22:41:09 -0700476
Steve French70ca7342005-09-22 16:32:06 -0700477 /* The right amount was read from socket - 4 bytes */
478 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700479
Steve French70ca7342005-09-22 16:32:06 -0700480 /* the first byte big endian of the length field,
481 is actually not part of the length but the type
482 with the most common, zero, as regular data */
483 temp = *((char *) smb_buffer);
484
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000485 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700486 but we convert it here so it is always manipulated
487 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700488 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700489 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700490
Joe Perchesb6b38f72010-04-21 03:50:45 +0000491 cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
Steve French70ca7342005-09-22 16:32:06 -0700492
493 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 continue;
Steve French70ca7342005-09-22 16:32:06 -0700495 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 cFYI(1, "Good RFC 1002 session rsp");
Steve Frenche4eb2952005-04-28 22:41:09 -0700497 continue;
Steve French70ca7342005-09-22 16:32:06 -0700498 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000499 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700500 an error on SMB negprot response */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000501 cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
502 pdu_length);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400503 /* give server a second to clean up */
504 msleep(1000);
505 /* always try 445 first on reconnect since we get NACK
506 * on some if we ever connected to port 139 (the NACK
507 * is since we do not begin with RFC1001 session
508 * initialize frame)
509 */
Jeff Layton32670392010-09-03 12:00:50 -0400510 cifs_set_port((struct sockaddr *)
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300511 &server->dstaddr, CIFS_PORT);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400512 cifs_reconnect(server);
513 csocket = server->ssocket;
514 wake_up(&server->response_q);
515 continue;
Steve French70ca7342005-09-22 16:32:06 -0700516 } else if (temp != (char) 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000517 cERROR(1, "Unknown RFC 1002 frame");
Steve French70ca7342005-09-22 16:32:06 -0700518 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
519 length);
Steve French46810cb2005-04-28 22:41:09 -0700520 cifs_reconnect(server);
521 csocket = server->ssocket;
522 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 }
524
525 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000527 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000528 cERROR(1, "Invalid size SMB length %d pdu_length %d",
529 length, pdu_length+4);
Steve Frenche4eb2952005-04-28 22:41:09 -0700530 cifs_reconnect(server);
531 csocket = server->ssocket;
532 wake_up(&server->response_q);
533 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700535
536 /* else length ok */
537 reconnect = 0;
538
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000540 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 memcpy(bigbuf, smallbuf, 4);
542 smb_buffer = bigbuf;
543 }
544 length = 0;
545 iov.iov_base = 4 + (char *)smb_buffer;
546 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000547 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 total_read += length) {
549 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
550 pdu_length - total_read, 0);
Jeff Layton522bbe62010-09-03 12:00:49 -0400551 if (server->tcpStatus == CifsExiting) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700552 /* then will exit */
553 reconnect = 2;
554 break;
555 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700556 cifs_reconnect(server);
557 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 /* Now we will reread sock */
560 reconnect = 1;
561 break;
Jeff Layton522bbe62010-09-03 12:00:49 -0400562 } else if (length == -ERESTARTSYS ||
563 length == -EAGAIN ||
564 length == -EINTR) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000566 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 threads to set tcpStatus
568 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000569 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700570 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000572 cERROR(1, "Received no data, expecting %d",
573 pdu_length - total_read);
Steve Frenche4eb2952005-04-28 22:41:09 -0700574 cifs_reconnect(server);
575 csocket = server->ssocket;
576 reconnect = 1;
577 break;
Steve French46810cb2005-04-28 22:41:09 -0700578 }
579 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000582 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 continue;
584
Jeff Layton9587fcf2011-02-01 08:40:43 -0500585 total_read += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000586
Jeff Layton9587fcf2011-02-01 08:40:43 -0500587 dump_smb(smb_buffer, total_read);
588 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read)) {
589 cifs_dump_mem("Bad SMB: ", smb_buffer,
590 total_read < 48 ? total_read : 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 continue;
592 }
593
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500594 mid_entry = NULL;
Steve Frenchfda35942011-01-20 18:06:34 +0000595 server->lstrp = jiffies;
596
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 spin_lock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500598 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
600
Steve French50c2f752007-07-13 00:33:32 +0000601 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
603 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000604 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000606 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000607 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000609 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700610 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000611 mid_entry->multiRsp =
612 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700613 break;
614 } else {
615 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000616 mid_entry->multiEnd =
617 true;
Steve French50c2f752007-07-13 00:33:32 +0000618 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700619 }
620 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000621 if (!isLargeBuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000622 cERROR(1, "1st trans2 resp needs bigbuf");
Steve Frenche4eb2952005-04-28 22:41:09 -0700623 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000624 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700626 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 mid_entry->resp_buf =
628 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000629 mid_entry->largeBuf =
630 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700631 bigbuf = NULL;
632 }
633 }
634 break;
Steve French50c2f752007-07-13 00:33:32 +0000635 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000637 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700638multi_t2_fnd:
Steve Frenche4eb2952005-04-28 22:41:09 -0700639 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700640#ifdef CONFIG_CIFS_STATS2
641 mid_entry->when_received = jiffies;
642#endif
Shirish Pargaonkar64474bd2011-02-03 14:31:18 -0600643 list_del_init(&mid_entry->qhead);
644 mid_entry->callback(mid_entry);
Steve Frenche4eb2952005-04-28 22:41:09 -0700645 break;
646 }
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500647 mid_entry = NULL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700648 }
649 spin_unlock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500650
651 if (mid_entry != NULL) {
Steve Frenchcd634992005-04-28 22:41:10 -0700652 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000653 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700654 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000655 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700656 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000657 else
Steve Frenchcd634992005-04-28 22:41:10 -0700658 smallbuf = NULL;
659 }
Steve French4b18f2a2008-04-29 00:06:05 +0000660 } else if (!is_valid_oplock_break(smb_buffer, server) &&
661 !isMultiRsp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cERROR(1, "No task to wake, unknown frame received! "
Jeff Layton80975312011-01-11 07:24:02 -0500663 "NumMids %d", atomic_read(&midCount));
Steve French50c2f752007-07-13 00:33:32 +0000664 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700665 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000666#ifdef CONFIG_CIFS_DEBUG2
667 cifs_dump_detail(smb_buffer);
668 cifs_dump_mids(server);
669#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000670
Steve Frenche4eb2952005-04-28 22:41:09 -0700671 }
672 } /* end while !EXITING */
673
Jeff Laytone7ddee92008-11-14 13:44:38 -0500674 /* take it off the list, if it's not already */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530675 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500676 list_del_init(&server->tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530677 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 spin_lock(&GlobalMid_Lock);
680 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000681 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000682 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000683
Steve French31ca3bc2005-04-28 22:41:11 -0700684 /* check if we have blocked requests that need to free */
685 /* Note that cifs_max_pending is normally 50, but
686 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000687 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000688 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700689 atomic_set(&server->inFlight, cifs_max_pending - 1);
690 /* We do not want to set the max_pending too low or we
691 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000693 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700695 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 to the same server - they now will see the session is in exit state
697 and get out of SendReceive. */
698 wake_up_all(&server->request_q);
699 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700700 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000701
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000702 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 sock_release(csocket);
704 server->ssocket = NULL;
705 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700706 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000707 cifs_buf_release(bigbuf);
708 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700709 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Jeff Layton9d783152011-01-11 07:24:01 -0500711 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 spin_lock(&GlobalMid_Lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500713 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
Jeff Layton9d783152011-01-11 07:24:01 -0500714 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500715 cFYI(1, "Clearing Mid 0x%x - issuing callback",
716 mid_entry->mid);
717 list_del_init(&mid_entry->qhead);
718 mid_entry->callback(mid_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
720 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700722 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724
Steve Frenchf1914012005-08-18 09:37:34 -0700725 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000726 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700728 /* due to delays on oplock break requests, we need
729 to wait at least 45 seconds before giving up
730 on a request getting a response and going ahead
731 and killing cifsd */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000732 cFYI(1, "Wait for exit from demultiplex thread");
Steve French31ca3bc2005-04-28 22:41:11 -0700733 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* if threads still have not exited they are probably never
735 coming home not much else we can do but free the memory */
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Jeff Laytonc359cf32007-11-16 22:22:06 +0000738 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400739 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700740 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400741
742 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000743 if (length > 0)
744 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
745 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000746
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400747 /* if server->tsk was NULL then wait for a signal before exiting */
748 if (!task_to_wake) {
749 set_current_state(TASK_INTERRUPTIBLE);
750 while (!signal_pending(current)) {
751 schedule();
752 set_current_state(TASK_INTERRUPTIBLE);
753 }
754 set_current_state(TASK_RUNNING);
755 }
756
Jeff Layton0468a2c2008-12-01 07:09:35 -0500757 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
Jeff Laytonc359cf32007-11-16 22:22:06 +0000760/* extract the host portion of the UNC string */
761static char *
762extract_hostname(const char *unc)
763{
764 const char *src;
765 char *dst, *delim;
766 unsigned int len;
767
768 /* skip double chars at beginning of string */
769 /* BB: check validity of these bytes? */
770 src = unc + 2;
771
772 /* delimiter between hostname and sharename is always '\\' now */
773 delim = strchr(src, '\\');
774 if (!delim)
775 return ERR_PTR(-EINVAL);
776
777 len = delim - src;
778 dst = kmalloc((len + 1), GFP_KERNEL);
779 if (dst == NULL)
780 return ERR_PTR(-ENOMEM);
781
782 memcpy(dst, src, len);
783 dst[len] = '\0';
784
785 return dst;
786}
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788static int
Steve French50c2f752007-07-13 00:33:32 +0000789cifs_parse_mount_options(char *options, const char *devname,
790 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791{
792 char *value;
793 char *data;
794 unsigned int temp_len, i, j;
795 char separator[2];
Jeff Layton9b9d6b242009-07-31 06:56:09 -0400796 short int override_uid = -1;
797 short int override_gid = -1;
798 bool uid_specified = false;
799 bool gid_specified = false;
Jeff Layton88463992010-11-22 15:31:03 -0500800 char *nodename = utsname()->nodename;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000803 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Jeff Layton88463992010-11-22 15:31:03 -0500805 /*
806 * does not have to be perfect mapping since field is
807 * informational, only used for servers that do not support
808 * port 445 and it can be overridden at mount time
809 */
Jeff Layton1397f2e2011-01-07 11:30:28 -0500810 memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
811 for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
Jeff Layton88463992010-11-22 15:31:03 -0500812 vol->source_rfc1001_name[i] = toupper(nodename[i]);
813
Jeff Layton1397f2e2011-01-07 11:30:28 -0500814 vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700815 /* null target name indicates to use *SMBSERVR default called name
816 if we end up sending RFC1001 session initialize */
817 vol->target_rfc1001_name[0] = 0;
Jeff Layton3e4b3e12010-07-19 18:00:17 -0400818 vol->cred_uid = current_uid();
819 vol->linux_uid = current_uid();
David Howellsa001e5b2008-11-14 10:38:47 +1100820 vol->linux_gid = current_gid();
Jeff Laytonf55ed1a2009-05-26 16:28:11 -0400821
822 /* default to only allowing write access to owner of the mount */
823 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Jeremy Allisonac670552005-06-22 17:26:35 -0700826 /* default is always to request posix paths. */
827 vol->posix_paths = 1;
Jeff Laytona0c92172009-05-27 15:40:47 -0400828 /* default to using server inode numbers where available */
829 vol->server_ino = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -0700830
Suresh Jayaraman6d20e842010-12-01 14:42:28 +0530831 vol->actimeo = CIFS_DEF_ACTIMEO;
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if (!options)
834 return 1;
835
Steve French50c2f752007-07-13 00:33:32 +0000836 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000837 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 separator[0] = options[4];
839 options += 5;
840 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000841 cFYI(1, "Null separator not allowed");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 }
843 }
Steve French50c2f752007-07-13 00:33:32 +0000844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 while ((data = strsep(&options, separator)) != NULL) {
846 if (!*data)
847 continue;
848 if ((value = strchr(data, '=')) != NULL)
849 *value++ = '\0';
850
Steve French50c2f752007-07-13 00:33:32 +0000851 /* Have to parse this before we parse for "user" */
852 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000854 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 vol->no_xattr = 1;
856 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000857 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 printk(KERN_WARNING
859 "CIFS: invalid or missing username\n");
860 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000861 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000862 /* null user, ie anonymous, authentication */
863 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
865 if (strnlen(value, 200) < 200) {
866 vol->username = value;
867 } else {
868 printk(KERN_WARNING "CIFS: username too long\n");
869 return 1;
870 }
871 } else if (strnicmp(data, "pass", 4) == 0) {
872 if (!value) {
873 vol->password = NULL;
874 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000875 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 /* check if string begins with double comma
877 since that would mean the password really
878 does start with a comma, and would not
879 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000880 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 vol->password = NULL;
882 continue;
883 }
884 }
885 temp_len = strlen(value);
886 /* removed password length check, NTLM passwords
887 can be arbitrarily long */
888
Steve French50c2f752007-07-13 00:33:32 +0000889 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 prematurely null terminated. Commas in password are
891 specified across the cifs mount interface by a double
892 comma ie ,, and a comma used as in other cases ie ','
893 as a parameter delimiter/separator is single and due
894 to the strsep above is temporarily zeroed. */
895
896 /* NB: password legally can have multiple commas and
897 the only illegal character in a password is null */
898
Steve French50c2f752007-07-13 00:33:32 +0000899 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700900 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 /* reinsert comma */
902 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000903 temp_len += 2; /* move after second comma */
904 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000906 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700907 separator[0]) {
908 /* skip second comma */
909 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000910 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* single comma indicating start
912 of next parm */
913 break;
914 }
915 }
916 temp_len++;
917 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000918 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 options = NULL;
920 } else {
921 value[temp_len] = 0;
922 /* point option to start of next parm */
923 options = value + temp_len + 1;
924 }
Steve French50c2f752007-07-13 00:33:32 +0000925 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 double commas to singles. Note that this ends up
927 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700928 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000929 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000930 printk(KERN_WARNING "CIFS: no memory "
931 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700932 return 1;
933 }
Steve French50c2f752007-07-13 00:33:32 +0000934 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000936 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700937 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* skip second comma */
939 i++;
940 }
941 }
942 vol->password[j] = 0;
943 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700944 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000945 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000946 printk(KERN_WARNING "CIFS: no memory "
947 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700948 return 1;
949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 strcpy(vol->password, value);
951 }
Jeff Layton58f7f682009-06-10 09:57:55 -0400952 } else if (!strnicmp(data, "ip", 2) ||
953 !strnicmp(data, "addr", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 if (!value || !*value) {
955 vol->UNCip = NULL;
Jeff Layton50b64e32009-06-02 06:55:20 -0400956 } else if (strnlen(value, INET6_ADDRSTRLEN) <
957 INET6_ADDRSTRLEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 vol->UNCip = value;
959 } else {
Steve French50c2f752007-07-13 00:33:32 +0000960 printk(KERN_WARNING "CIFS: ip address "
961 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return 1;
963 }
Steve French50c2f752007-07-13 00:33:32 +0000964 } else if (strnicmp(data, "sec", 3) == 0) {
965 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000966 cERROR(1, "no security value specified");
Steve French50c2f752007-07-13 00:33:32 +0000967 continue;
968 } else if (strnicmp(value, "krb5i", 5) == 0) {
969 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000970 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800971 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000972 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
973 CIFSSEC_MAY_KRB5; */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000974 cERROR(1, "Krb5 cifs privacy not supported");
Steve Frenchbf820672005-12-01 22:32:42 -0800975 return 1;
976 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000977 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchac683922009-05-06 04:16:04 +0000978 } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
979 vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
980 CIFSSEC_MUST_SIGN;
981 } else if (strnicmp(value, "ntlmssp", 7) == 0) {
982 vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000985 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800986 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000987 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000989 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000990 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "ntlm", 4) == 0) {
992 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800994 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000995 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000996 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000997#ifdef CONFIG_CIFS_WEAK_PW_HASH
998 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000999 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001000#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001001 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001002 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001003 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001004 cERROR(1, "bad security option: %s", value);
Steve French50c2f752007-07-13 00:33:32 +00001005 return 1;
1006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 } else if ((strnicmp(data, "unc", 3) == 0)
1008 || (strnicmp(data, "target", 6) == 0)
1009 || (strnicmp(data, "path", 4) == 0)) {
1010 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001011 printk(KERN_WARNING "CIFS: invalid path to "
1012 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return 1; /* needs_arg; */
1014 }
1015 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001016 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001017 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001019 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (strncmp(vol->UNC, "//", 2) == 0) {
1021 vol->UNC[0] = '\\';
1022 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001023 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001025 "CIFS: UNC Path does not begin "
1026 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return 1;
1028 }
1029 } else {
1030 printk(KERN_WARNING "CIFS: UNC name too long\n");
1031 return 1;
1032 }
1033 } else if ((strnicmp(data, "domain", 3) == 0)
1034 || (strnicmp(data, "workgroup", 5) == 0)) {
1035 if (!value || !*value) {
1036 printk(KERN_WARNING "CIFS: invalid domain name\n");
1037 return 1; /* needs_arg; */
1038 }
1039 /* BB are there cases in which a comma can be valid in
1040 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001041 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 vol->domainname = value;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001043 cFYI(1, "Domain name set");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 } else {
Steve French50c2f752007-07-13 00:33:32 +00001045 printk(KERN_WARNING "CIFS: domain name too "
1046 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return 1;
1048 }
Ben Greear3eb9a882010-09-01 17:06:02 -07001049 } else if (strnicmp(data, "srcaddr", 7) == 0) {
1050 vol->srcaddr.ss_family = AF_UNSPEC;
1051
1052 if (!value || !*value) {
1053 printk(KERN_WARNING "CIFS: srcaddr value"
1054 " not specified.\n");
1055 return 1; /* needs_arg; */
1056 }
1057 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
1058 value, strlen(value));
Dan Carpenterb235f372010-10-25 07:02:56 +02001059 if (i == 0) {
Ben Greear3eb9a882010-09-01 17:06:02 -07001060 printk(KERN_WARNING "CIFS: Could not parse"
1061 " srcaddr: %s\n",
1062 value);
1063 return 1;
1064 }
Steve French50c2f752007-07-13 00:33:32 +00001065 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1066 if (!value || !*value) {
1067 printk(KERN_WARNING
1068 "CIFS: invalid path prefix\n");
1069 return 1; /* needs_argument */
1070 }
1071 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001072 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001073 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001074 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1075 if (vol->prepath == NULL)
1076 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001077 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001078 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001079 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001080 } else
Steve French50c2f752007-07-13 00:33:32 +00001081 strcpy(vol->prepath, value);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001082 cFYI(1, "prefix path %s", vol->prepath);
Steve French50c2f752007-07-13 00:33:32 +00001083 } else {
1084 printk(KERN_WARNING "CIFS: prefix too long\n");
1085 return 1;
1086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 } else if (strnicmp(data, "iocharset", 9) == 0) {
1088 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001089 printk(KERN_WARNING "CIFS: invalid iocharset "
1090 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return 1; /* needs_arg; */
1092 }
1093 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001094 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001096 /* if iocharset not set then load_nls_default
1097 is used by caller */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001098 cFYI(1, "iocharset set to %s", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 } else {
Steve French63135e02007-07-17 17:34:02 +00001100 printk(KERN_WARNING "CIFS: iocharset name "
1101 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return 1;
1103 }
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001104 } else if (!strnicmp(data, "uid", 3) && value && *value) {
1105 vol->linux_uid = simple_strtoul(value, &value, 0);
1106 uid_specified = true;
Jeff Laytonbd763312011-01-11 10:33:24 -05001107 } else if (!strnicmp(data, "cruid", 5) && value && *value) {
1108 vol->cred_uid = simple_strtoul(value, &value, 0);
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001109 } else if (!strnicmp(data, "forceuid", 8)) {
1110 override_uid = 1;
1111 } else if (!strnicmp(data, "noforceuid", 10)) {
1112 override_uid = 0;
1113 } else if (!strnicmp(data, "gid", 3) && value && *value) {
1114 vol->linux_gid = simple_strtoul(value, &value, 0);
1115 gid_specified = true;
1116 } else if (!strnicmp(data, "forcegid", 8)) {
1117 override_gid = 1;
1118 } else if (!strnicmp(data, "noforcegid", 10)) {
1119 override_gid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 } else if (strnicmp(data, "file_mode", 4) == 0) {
1121 if (value && *value) {
1122 vol->file_mode =
1123 simple_strtoul(value, &value, 0);
1124 }
1125 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1126 if (value && *value) {
1127 vol->dir_mode =
1128 simple_strtoul(value, &value, 0);
1129 }
1130 } else if (strnicmp(data, "dirmode", 4) == 0) {
1131 if (value && *value) {
1132 vol->dir_mode =
1133 simple_strtoul(value, &value, 0);
1134 }
1135 } else if (strnicmp(data, "port", 4) == 0) {
1136 if (value && *value) {
1137 vol->port =
1138 simple_strtoul(value, &value, 0);
1139 }
1140 } else if (strnicmp(data, "rsize", 5) == 0) {
1141 if (value && *value) {
1142 vol->rsize =
1143 simple_strtoul(value, &value, 0);
1144 }
1145 } else if (strnicmp(data, "wsize", 5) == 0) {
1146 if (value && *value) {
1147 vol->wsize =
1148 simple_strtoul(value, &value, 0);
1149 }
1150 } else if (strnicmp(data, "sockopt", 5) == 0) {
Steve French6a5fa2362010-01-01 01:28:43 +00001151 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001152 cERROR(1, "no socket option specified");
Steve French6a5fa2362010-01-01 01:28:43 +00001153 continue;
1154 } else if (strnicmp(value, "TCP_NODELAY", 11) == 0) {
1155 vol->sockopt_tcp_nodelay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
1157 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1158 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001159 cFYI(1, "invalid (empty) netbiosname");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 } else {
Jeff Layton1397f2e2011-01-07 11:30:28 -05001161 memset(vol->source_rfc1001_name, 0x20,
1162 RFC1001_NAME_LEN);
1163 /*
1164 * FIXME: are there cases in which a comma can
1165 * be valid in workstation netbios name (and
1166 * need special handling)?
1167 */
1168 for (i = 0; i < RFC1001_NAME_LEN; i++) {
1169 /* don't ucase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001170 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 break;
Jeff Layton1397f2e2011-01-07 11:30:28 -05001172 vol->source_rfc1001_name[i] = value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 }
1174 /* The string has 16th byte zero still from
1175 set at top of the function */
Jeff Layton1397f2e2011-01-07 11:30:28 -05001176 if (i == RFC1001_NAME_LEN && value[i] != 0)
Steve French50c2f752007-07-13 00:33:32 +00001177 printk(KERN_WARNING "CIFS: netbiosname"
1178 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001179 }
1180 } else if (strnicmp(data, "servern", 7) == 0) {
1181 /* servernetbiosname specified override *SMBSERVER */
1182 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001183 cFYI(1, "empty server netbiosname specified");
Steve Frencha10faeb22005-08-22 21:38:31 -07001184 } else {
1185 /* last byte, type, is 0x20 for servr type */
Jeff Layton1397f2e2011-01-07 11:30:28 -05001186 memset(vol->target_rfc1001_name, 0x20,
1187 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001188
Steve French50c2f752007-07-13 00:33:32 +00001189 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001190 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001191 valid in this workstation netbios name
1192 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001193
Steve French50c2f752007-07-13 00:33:32 +00001194 /* user or mount helper must uppercase
1195 the netbiosname */
1196 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001197 break;
1198 else
Steve French50c2f752007-07-13 00:33:32 +00001199 vol->target_rfc1001_name[i] =
1200 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001201 }
1202 /* The string has 16th byte zero still from
1203 set at top of the function */
Jeff Layton1397f2e2011-01-07 11:30:28 -05001204 if (i == RFC1001_NAME_LEN && value[i] != 0)
Steve French50c2f752007-07-13 00:33:32 +00001205 printk(KERN_WARNING "CIFS: server net"
1206 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 }
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301208 } else if (strnicmp(data, "actimeo", 7) == 0) {
1209 if (value && *value) {
1210 vol->actimeo = HZ * simple_strtoul(value,
1211 &value, 0);
1212 if (vol->actimeo > CIFS_MAX_ACTIMEO) {
1213 cERROR(1, "CIFS: attribute cache"
1214 "timeout too large");
1215 return 1;
1216 }
1217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 } else if (strnicmp(data, "credentials", 4) == 0) {
1219 /* ignore */
1220 } else if (strnicmp(data, "version", 3) == 0) {
1221 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 /* ignore */
Steve French71a394f2009-06-26 04:07:18 +00001224 } else if (strnicmp(data, "rw", 2) == 0) {
1225 /* ignore */
1226 } else if (strnicmp(data, "ro", 2) == 0) {
1227 /* ignore */
Steve Frenchedf1ae42008-10-29 00:47:57 +00001228 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1229 vol->noblocksnd = 1;
1230 } else if (strnicmp(data, "noautotune", 10) == 0) {
1231 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 } else if ((strnicmp(data, "suid", 4) == 0) ||
1233 (strnicmp(data, "nosuid", 6) == 0) ||
1234 (strnicmp(data, "exec", 4) == 0) ||
1235 (strnicmp(data, "noexec", 6) == 0) ||
1236 (strnicmp(data, "nodev", 5) == 0) ||
1237 (strnicmp(data, "noauto", 6) == 0) ||
1238 (strnicmp(data, "dev", 3) == 0)) {
1239 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001240 uses these opts to set flags, and the flags are read
1241 by the kernel vfs layer before we get here (ie
1242 before read super) so there is no point trying to
1243 parse these options again and set anything and it
1244 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 } else if (strnicmp(data, "hard", 4) == 0) {
1247 vol->retry = 1;
1248 } else if (strnicmp(data, "soft", 4) == 0) {
1249 vol->retry = 0;
1250 } else if (strnicmp(data, "perm", 4) == 0) {
1251 vol->noperm = 0;
1252 } else if (strnicmp(data, "noperm", 6) == 0) {
1253 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001254 } else if (strnicmp(data, "mapchars", 8) == 0) {
1255 vol->remap = 1;
1256 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1257 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001258 } else if (strnicmp(data, "sfu", 3) == 0) {
1259 vol->sfu_emul = 1;
1260 } else if (strnicmp(data, "nosfu", 5) == 0) {
1261 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001262 } else if (strnicmp(data, "nodfs", 5) == 0) {
1263 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001264 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1265 vol->posix_paths = 1;
1266 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1267 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001268 } else if (strnicmp(data, "nounix", 6) == 0) {
1269 vol->no_linux_ext = 1;
1270 } else if (strnicmp(data, "nolinux", 7) == 0) {
1271 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001272 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001273 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001274 vol->nocase = 1;
Jeff Laytonf636a342010-07-26 10:29:58 -04001275 } else if (strnicmp(data, "mand", 4) == 0) {
1276 /* ignore */
1277 } else if (strnicmp(data, "nomand", 6) == 0) {
1278 /* ignore */
1279 } else if (strnicmp(data, "_netdev", 7) == 0) {
1280 /* ignore */
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001281 } else if (strnicmp(data, "brl", 3) == 0) {
1282 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001283 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001284 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001285 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001286 /* turn off mandatory locking in mode
1287 if remote locking is turned off since the
1288 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001289 if (vol->file_mode ==
1290 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001291 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001292 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1293 /* will take the shorter form "forcemand" as well */
1294 /* This mount option will force use of mandatory
1295 (DOS/Windows style) byte range locks, instead of
1296 using posix advisory byte range locks, even if the
1297 Unix extensions are available and posix locks would
1298 be supported otherwise. If Unix extensions are not
1299 negotiated this has no effect since mandatory locks
1300 would be used (mandatory locks is all that those
1301 those servers support) */
1302 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 } else if (strnicmp(data, "setuids", 7) == 0) {
1304 vol->setuids = 1;
1305 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1306 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001307 } else if (strnicmp(data, "dynperm", 7) == 0) {
1308 vol->dynperm = true;
1309 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1310 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 } else if (strnicmp(data, "nohard", 6) == 0) {
1312 vol->retry = 0;
1313 } else if (strnicmp(data, "nosoft", 6) == 0) {
1314 vol->retry = 1;
1315 } else if (strnicmp(data, "nointr", 6) == 0) {
1316 vol->intr = 0;
1317 } else if (strnicmp(data, "intr", 4) == 0) {
1318 vol->intr = 1;
Steve Frenchbe652442009-02-23 15:21:59 +00001319 } else if (strnicmp(data, "nostrictsync", 12) == 0) {
1320 vol->nostrictsync = 1;
1321 } else if (strnicmp(data, "strictsync", 10) == 0) {
1322 vol->nostrictsync = 0;
Steve French50c2f752007-07-13 00:33:32 +00001323 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001325 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001327 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001328 vol->cifs_acl = 1;
1329 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1330 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001331 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001333 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001335 } else if (strnicmp(data, "locallease", 6) == 0) {
1336 vol->local_lease = 1;
Steve French50c2f752007-07-13 00:33:32 +00001337 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001338 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001339 } else if (strnicmp(data, "seal", 4) == 0) {
1340 /* we do not do the following in secFlags because seal
1341 is a per tree connection (mount) not a per socket
1342 or per-smb connection option in the protocol */
1343 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1344 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001345 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001347 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 vol->direct_io = 1;
Pavel Shilovskyd39454f2011-01-24 14:16:35 -05001349 } else if (strnicmp(data, "strictcache", 11) == 0) {
1350 vol->strict_io = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001352 printk(KERN_WARNING "CIFS: Mount option noac not "
1353 "supported. Instead set "
1354 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05301355 } else if (strnicmp(data, "fsc", 3) == 0) {
Suresh Jayaraman607a5692010-11-24 17:49:05 +05301356#ifndef CONFIG_CIFS_FSCACHE
1357 cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
1358 "kernel config option set");
1359 return 1;
1360#endif
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05301361 vol->fsc = true;
Stefan Metzmacher736a3322010-07-30 14:56:00 +02001362 } else if (strnicmp(data, "mfsymlinks", 10) == 0) {
1363 vol->mfsymlinks = true;
Jeff Layton0eb8a132010-10-06 19:51:12 -04001364 } else if (strnicmp(data, "multiuser", 8) == 0) {
1365 vol->multiuser = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 } else
Steve French50c2f752007-07-13 00:33:32 +00001367 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1368 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
1370 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001371 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001372 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1373 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 return 1;
1375 }
1376 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001377 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001378 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001380 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (strncmp(vol->UNC, "//", 2) == 0) {
1382 vol->UNC[0] = '\\';
1383 vol->UNC[1] = '\\';
1384 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001385 printk(KERN_WARNING "CIFS: UNC Path does not "
1386 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 return 1;
1388 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001389 value = strpbrk(vol->UNC+2, "/\\");
1390 if (value)
1391 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
1393 printk(KERN_WARNING "CIFS: UNC name too long\n");
1394 return 1;
1395 }
1396 }
Jeff Layton0eb8a132010-10-06 19:51:12 -04001397
1398 if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
1399 cERROR(1, "Multiuser mounts currently require krb5 "
1400 "authentication!");
1401 return 1;
1402 }
1403
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001404 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 vol->UNCip = &vol->UNC[2];
1406
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001407 if (uid_specified)
1408 vol->override_uid = override_uid;
1409 else if (override_uid == 1)
1410 printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
1411 "specified with no uid= option.\n");
1412
1413 if (gid_specified)
1414 vol->override_gid = override_gid;
1415 else if (override_gid == 1)
1416 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
1417 "specified with no gid= option.\n");
1418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 return 0;
1420}
1421
Ben Greear3eb9a882010-09-01 17:06:02 -07001422/** Returns true if srcaddr isn't specified and rhs isn't
1423 * specified, or if srcaddr is specified and
1424 * matches the IP address of the rhs argument.
1425 */
Jeff Layton45151482010-07-06 20:43:02 -04001426static bool
Ben Greear3eb9a882010-09-01 17:06:02 -07001427srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
1428{
1429 switch (srcaddr->sa_family) {
1430 case AF_UNSPEC:
1431 return (rhs->sa_family == AF_UNSPEC);
1432 case AF_INET: {
1433 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1434 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1435 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1436 }
1437 case AF_INET6: {
1438 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1439 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
1440 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1441 }
1442 default:
1443 WARN_ON(1);
1444 return false; /* don't expect to be here */
1445 }
1446}
1447
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001448/*
1449 * If no port is specified in addr structure, we try to match with 445 port
1450 * and if it fails - with 139 ports. It should be called only if address
1451 * families of server and addr are equal.
1452 */
1453static bool
1454match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
1455{
1456 unsigned short int port, *sport;
1457
1458 switch (addr->sa_family) {
1459 case AF_INET:
1460 sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
1461 port = ((struct sockaddr_in *) addr)->sin_port;
1462 break;
1463 case AF_INET6:
1464 sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
1465 port = ((struct sockaddr_in6 *) addr)->sin6_port;
1466 break;
1467 default:
1468 WARN_ON(1);
1469 return false;
1470 }
1471
1472 if (!port) {
1473 port = htons(CIFS_PORT);
1474 if (port == *sport)
1475 return true;
1476
1477 port = htons(RFC1001_PORT);
1478 }
1479
1480 return port == *sport;
1481}
Ben Greear3eb9a882010-09-01 17:06:02 -07001482
1483static bool
1484match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1485 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
Jeff Layton45151482010-07-06 20:43:02 -04001487 switch (addr->sa_family) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001488 case AF_INET: {
1489 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1490 struct sockaddr_in *srv_addr4 =
1491 (struct sockaddr_in *)&server->dstaddr;
1492
1493 if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
Jeff Layton45151482010-07-06 20:43:02 -04001494 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001495 break;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001496 }
1497 case AF_INET6: {
1498 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1499 struct sockaddr_in6 *srv_addr6 =
1500 (struct sockaddr_in6 *)&server->dstaddr;
1501
Jeff Layton45151482010-07-06 20:43:02 -04001502 if (!ipv6_addr_equal(&addr6->sin6_addr,
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001503 &srv_addr6->sin6_addr))
Jeff Layton45151482010-07-06 20:43:02 -04001504 return false;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001505 if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
Jeff Layton45151482010-07-06 20:43:02 -04001506 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001507 break;
1508 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001509 default:
1510 WARN_ON(1);
1511 return false; /* don't expect to be here */
1512 }
Jeff Layton45151482010-07-06 20:43:02 -04001513
Ben Greear3eb9a882010-09-01 17:06:02 -07001514 if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
1515 return false;
1516
Jeff Layton45151482010-07-06 20:43:02 -04001517 return true;
1518}
1519
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001520static bool
1521match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
1522{
1523 unsigned int secFlags;
1524
1525 if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
1526 secFlags = vol->secFlg;
1527 else
1528 secFlags = global_secflags | vol->secFlg;
1529
1530 switch (server->secType) {
1531 case LANMAN:
1532 if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
1533 return false;
1534 break;
1535 case NTLMv2:
1536 if (!(secFlags & CIFSSEC_MAY_NTLMV2))
1537 return false;
1538 break;
1539 case NTLM:
1540 if (!(secFlags & CIFSSEC_MAY_NTLM))
1541 return false;
1542 break;
1543 case Kerberos:
1544 if (!(secFlags & CIFSSEC_MAY_KRB5))
1545 return false;
1546 break;
1547 case RawNTLMSSP:
1548 if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
1549 return false;
1550 break;
1551 default:
1552 /* shouldn't happen */
1553 return false;
1554 }
1555
1556 /* now check if signing mode is acceptible */
1557 if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
1558 (server->secMode & SECMODE_SIGN_REQUIRED))
1559 return false;
1560 else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
1561 (server->secMode &
1562 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
1563 return false;
1564
1565 return true;
1566}
1567
Jeff Layton45151482010-07-06 20:43:02 -04001568static struct TCP_Server_Info *
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001569cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
Jeff Layton45151482010-07-06 20:43:02 -04001570{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001571 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301573 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001574 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Rob Landleyf1d0c992011-01-22 15:44:05 -06001575 if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
1576 continue;
1577
Ben Greear3eb9a882010-09-01 17:06:02 -07001578 if (!match_address(server, addr,
1579 (struct sockaddr *)&vol->srcaddr))
Jeff Layton45151482010-07-06 20:43:02 -04001580 continue;
Steve French50c2f752007-07-13 00:33:32 +00001581
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001582 if (!match_port(server, addr))
1583 continue;
1584
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001585 if (!match_security(server, vol))
1586 continue;
1587
Jeff Laytone7ddee92008-11-14 13:44:38 -05001588 ++server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301589 spin_unlock(&cifs_tcp_ses_lock);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001590 cFYI(1, "Existing tcp session with server found");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001591 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301593 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 return NULL;
1595}
1596
Jeff Layton14fbf502008-11-14 13:53:46 -05001597static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001598cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001600 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301602 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001603 if (--server->srv_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301604 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001605 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001607
Rob Landleyf1d0c992011-01-22 15:44:05 -06001608 put_net(cifs_net_ns(server));
1609
Jeff Laytone7ddee92008-11-14 13:44:38 -05001610 list_del_init(&server->tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301611 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001612
Jeff Laytonc74093b2011-01-11 07:24:23 -05001613 cancel_delayed_work_sync(&server->echo);
1614
Jeff Laytone7ddee92008-11-14 13:44:38 -05001615 spin_lock(&GlobalMid_Lock);
1616 server->tcpStatus = CifsExiting;
1617 spin_unlock(&GlobalMid_Lock);
1618
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05001619 cifs_crypto_shash_release(server);
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301620 cifs_fscache_release_client_cookie(server);
1621
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05001622 kfree(server->session_key.response);
1623 server->session_key.response = NULL;
1624 server->session_key.len = 0;
1625
Jeff Laytone7ddee92008-11-14 13:44:38 -05001626 task = xchg(&server->tsk, NULL);
1627 if (task)
1628 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629}
1630
Jeff Layton63c038c2008-12-01 18:41:46 -05001631static struct TCP_Server_Info *
1632cifs_get_tcp_session(struct smb_vol *volume_info)
1633{
1634 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001635 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05001636 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1637 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1638 int rc;
1639
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001640 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05001641
Joe Perchesb6b38f72010-04-21 03:50:45 +00001642 cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001643
Jeff Layton63c038c2008-12-01 18:41:46 -05001644 if (volume_info->UNCip && volume_info->UNC) {
Jeff Layton50d97162010-07-06 20:43:01 -04001645 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
1646 volume_info->UNCip,
David Howells67b76262010-07-22 18:33:01 +01001647 strlen(volume_info->UNCip),
Jeff Layton50d97162010-07-06 20:43:01 -04001648 volume_info->port);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001649 if (!rc) {
Jeff Layton63c038c2008-12-01 18:41:46 -05001650 /* we failed translating address */
1651 rc = -EINVAL;
1652 goto out_err;
1653 }
Jeff Layton63c038c2008-12-01 18:41:46 -05001654 } else if (volume_info->UNCip) {
1655 /* BB using ip addr as tcp_ses name to connect to the
1656 DFS root below */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001657 cERROR(1, "Connecting to DFS root not implemented yet");
Jeff Layton63c038c2008-12-01 18:41:46 -05001658 rc = -EINVAL;
1659 goto out_err;
1660 } else /* which tcp_sess DFS root would we conect to */ {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001661 cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
1662 "unc=//192.168.1.100/public) specified");
Jeff Layton63c038c2008-12-01 18:41:46 -05001663 rc = -EINVAL;
1664 goto out_err;
1665 }
1666
1667 /* see if we already have a matching tcp_ses */
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001668 tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05001669 if (tcp_ses)
1670 return tcp_ses;
1671
1672 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1673 if (!tcp_ses) {
1674 rc = -ENOMEM;
1675 goto out_err;
1676 }
1677
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05001678 rc = cifs_crypto_shash_allocate(tcp_ses);
1679 if (rc) {
1680 cERROR(1, "could not setup hash structures rc %d", rc);
1681 goto out_err;
1682 }
1683
Rob Landleyf1d0c992011-01-22 15:44:05 -06001684 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
Jeff Layton63c038c2008-12-01 18:41:46 -05001685 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1686 if (IS_ERR(tcp_ses->hostname)) {
1687 rc = PTR_ERR(tcp_ses->hostname);
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05001688 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001689 }
1690
1691 tcp_ses->noblocksnd = volume_info->noblocksnd;
1692 tcp_ses->noautotune = volume_info->noautotune;
Steve French6a5fa2362010-01-01 01:28:43 +00001693 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
Jeff Layton63c038c2008-12-01 18:41:46 -05001694 atomic_set(&tcp_ses->inFlight, 0);
1695 init_waitqueue_head(&tcp_ses->response_q);
1696 init_waitqueue_head(&tcp_ses->request_q);
1697 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1698 mutex_init(&tcp_ses->srv_mutex);
1699 memcpy(tcp_ses->workstation_RFC1001_name,
1700 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1701 memcpy(tcp_ses->server_RFC1001_name,
1702 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05001703 tcp_ses->session_estab = false;
Jeff Layton63c038c2008-12-01 18:41:46 -05001704 tcp_ses->sequence_number = 0;
Steve Frenchfda35942011-01-20 18:06:34 +00001705 tcp_ses->lstrp = jiffies;
Jeff Layton63c038c2008-12-01 18:41:46 -05001706 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1707 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001708 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
Jeff Layton63c038c2008-12-01 18:41:46 -05001709
1710 /*
1711 * at this point we are the only ones with the pointer
1712 * to the struct since the kernel thread not created yet
1713 * no need to spinlock this init of tcpStatus or srv_count
1714 */
1715 tcp_ses->tcpStatus = CifsNew;
Ben Greear3eb9a882010-09-01 17:06:02 -07001716 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
1717 sizeof(tcp_ses->srcaddr));
Jeff Layton63c038c2008-12-01 18:41:46 -05001718 ++tcp_ses->srv_count;
1719
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001720 if (addr.ss_family == AF_INET6) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001721 cFYI(1, "attempting ipv6 connect");
Jeff Layton63c038c2008-12-01 18:41:46 -05001722 /* BB should we allow ipv6 on port 139? */
1723 /* other OS never observed in Wild doing 139 with v6 */
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001724 memcpy(&tcp_ses->dstaddr, sin_server6,
1725 sizeof(struct sockaddr_in6));
1726 } else
1727 memcpy(&tcp_ses->dstaddr, sin_server,
1728 sizeof(struct sockaddr_in));
1729
1730 rc = ip_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001731 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001732 cERROR(1, "Error connecting to socket. Aborting operation");
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05001733 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001734 }
1735
1736 /*
1737 * since we're in a cifs function already, we know that
1738 * this will succeed. No need for try_module_get().
1739 */
1740 __module_get(THIS_MODULE);
1741 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1742 tcp_ses, "cifsd");
1743 if (IS_ERR(tcp_ses->tsk)) {
1744 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001745 cERROR(1, "error %d create cifsd thread", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05001746 module_put(THIS_MODULE);
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05001747 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001748 }
1749
1750 /* thread spawned, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301751 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001752 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301753 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001754
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301755 cifs_fscache_get_client_cookie(tcp_ses);
1756
Jeff Laytonc74093b2011-01-11 07:24:23 -05001757 /* queue echo request delayed work */
1758 queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
1759
Jeff Layton63c038c2008-12-01 18:41:46 -05001760 return tcp_ses;
1761
Shirish Pargaonkarf7c54452010-10-26 18:10:24 -05001762out_err_crypto_release:
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05001763 cifs_crypto_shash_release(tcp_ses);
1764
Rob Landleyf1d0c992011-01-22 15:44:05 -06001765 put_net(cifs_net_ns(tcp_ses));
1766
Jeff Layton63c038c2008-12-01 18:41:46 -05001767out_err:
1768 if (tcp_ses) {
Steve French8347a5c2009-10-06 18:31:29 +00001769 if (!IS_ERR(tcp_ses->hostname))
1770 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05001771 if (tcp_ses->ssocket)
1772 sock_release(tcp_ses->ssocket);
1773 kfree(tcp_ses);
1774 }
1775 return ERR_PTR(rc);
1776}
1777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778static struct cifsSesInfo *
Jeff Layton4ff67b72010-07-06 20:43:02 -04001779cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 struct cifsSesInfo *ses;
1782
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301783 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04001784 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1785 switch (server->secType) {
1786 case Kerberos:
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001787 if (vol->cred_uid != ses->cred_uid)
Jeff Layton4ff67b72010-07-06 20:43:02 -04001788 continue;
1789 break;
1790 default:
1791 /* anything else takes username/password */
1792 if (strncmp(ses->userName, vol->username,
1793 MAX_USERNAME_SIZE))
1794 continue;
1795 if (strlen(vol->username) != 0 &&
Jeff Layton24e6cf92010-08-23 11:38:04 -04001796 ses->password != NULL &&
Jeff Laytonfc87a402010-08-18 13:13:39 -04001797 strncmp(ses->password,
1798 vol->password ? vol->password : "",
Jeff Layton4ff67b72010-07-06 20:43:02 -04001799 MAX_PASSWORD_SIZE))
1800 continue;
1801 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001802 ++ses->ses_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301803 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001804 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301806 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 return NULL;
1808}
1809
Jeff Layton14fbf502008-11-14 13:53:46 -05001810static void
1811cifs_put_smb_ses(struct cifsSesInfo *ses)
1812{
1813 int xid;
1814 struct TCP_Server_Info *server = ses->server;
1815
Jeff Layton36988c72010-04-24 07:57:43 -04001816 cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301817 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001818 if (--ses->ses_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301819 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001820 return;
1821 }
1822
1823 list_del_init(&ses->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301824 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001825
1826 if (ses->status == CifsGood) {
1827 xid = GetXid();
1828 CIFSSMBLogoff(xid, ses);
1829 _FreeXid(xid);
1830 }
1831 sesInfoFree(ses);
1832 cifs_put_tcp_session(server);
1833}
1834
Jeff Layton36988c72010-04-24 07:57:43 -04001835static struct cifsSesInfo *
1836cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1837{
1838 int rc = -ENOMEM, xid;
1839 struct cifsSesInfo *ses;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001840 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
1841 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
Jeff Layton36988c72010-04-24 07:57:43 -04001842
1843 xid = GetXid();
1844
Jeff Layton4ff67b72010-07-06 20:43:02 -04001845 ses = cifs_find_smb_ses(server, volume_info);
Jeff Layton36988c72010-04-24 07:57:43 -04001846 if (ses) {
1847 cFYI(1, "Existing smb sess found (status=%d)", ses->status);
1848
Jeff Layton36988c72010-04-24 07:57:43 -04001849 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001850 rc = cifs_negotiate_protocol(xid, ses);
1851 if (rc) {
1852 mutex_unlock(&ses->session_mutex);
1853 /* problem -- put our ses reference */
1854 cifs_put_smb_ses(ses);
1855 FreeXid(xid);
1856 return ERR_PTR(rc);
1857 }
Jeff Layton36988c72010-04-24 07:57:43 -04001858 if (ses->need_reconnect) {
1859 cFYI(1, "Session needs reconnect");
1860 rc = cifs_setup_session(xid, ses,
1861 volume_info->local_nls);
1862 if (rc) {
1863 mutex_unlock(&ses->session_mutex);
1864 /* problem -- put our reference */
1865 cifs_put_smb_ses(ses);
1866 FreeXid(xid);
1867 return ERR_PTR(rc);
1868 }
1869 }
1870 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04001871
1872 /* existing SMB ses has a server reference already */
1873 cifs_put_tcp_session(server);
Jeff Layton36988c72010-04-24 07:57:43 -04001874 FreeXid(xid);
1875 return ses;
1876 }
1877
1878 cFYI(1, "Existing smb sess not found");
1879 ses = sesInfoAlloc();
1880 if (ses == NULL)
1881 goto get_ses_fail;
1882
1883 /* new SMB session uses our server ref */
1884 ses->server = server;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001885 if (server->dstaddr.ss_family == AF_INET6)
1886 sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001887 else
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001888 sprintf(ses->serverName, "%pI4", &addr->sin_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001889
1890 if (volume_info->username)
1891 strncpy(ses->userName, volume_info->username,
1892 MAX_USERNAME_SIZE);
1893
1894 /* volume_info->password freed at unmount */
1895 if (volume_info->password) {
1896 ses->password = kstrdup(volume_info->password, GFP_KERNEL);
1897 if (!ses->password)
1898 goto get_ses_fail;
1899 }
1900 if (volume_info->domainname) {
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05001901 ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL);
1902 if (!ses->domainName)
1903 goto get_ses_fail;
Jeff Layton36988c72010-04-24 07:57:43 -04001904 }
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001905 ses->cred_uid = volume_info->cred_uid;
Jeff Layton36988c72010-04-24 07:57:43 -04001906 ses->linux_uid = volume_info->linux_uid;
1907 ses->overrideSecFlg = volume_info->secFlg;
1908
1909 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001910 rc = cifs_negotiate_protocol(xid, ses);
1911 if (!rc)
1912 rc = cifs_setup_session(xid, ses, volume_info->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04001913 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00001914 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04001915 goto get_ses_fail;
1916
1917 /* success, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301918 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001919 list_add(&ses->smb_ses_list, &server->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301920 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001921
1922 FreeXid(xid);
1923 return ses;
1924
1925get_ses_fail:
1926 sesInfoFree(ses);
1927 FreeXid(xid);
1928 return ERR_PTR(rc);
1929}
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001932cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933{
1934 struct list_head *tmp;
1935 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301937 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001938 list_for_each(tmp, &ses->tcon_list) {
1939 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1940 if (tcon->tidStatus == CifsExiting)
1941 continue;
1942 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 continue;
1944
Jeff Laytonf1987b42008-11-15 11:12:47 -05001945 ++tcon->tc_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301946 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return tcon;
1948 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301949 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 return NULL;
1951}
1952
Jeff Laytonf1987b42008-11-15 11:12:47 -05001953static void
1954cifs_put_tcon(struct cifsTconInfo *tcon)
1955{
1956 int xid;
1957 struct cifsSesInfo *ses = tcon->ses;
1958
Jeff Laytond00c28d2010-04-24 07:57:44 -04001959 cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301960 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001961 if (--tcon->tc_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301962 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001963 return;
1964 }
1965
1966 list_del_init(&tcon->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301967 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001968
1969 xid = GetXid();
1970 CIFSSMBTDis(xid, tcon);
1971 _FreeXid(xid);
1972
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301973 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00001974 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001975 cifs_put_smb_ses(ses);
1976}
1977
Jeff Laytond00c28d2010-04-24 07:57:44 -04001978static struct cifsTconInfo *
1979cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
1980{
1981 int rc, xid;
1982 struct cifsTconInfo *tcon;
1983
1984 tcon = cifs_find_tcon(ses, volume_info->UNC);
1985 if (tcon) {
1986 cFYI(1, "Found match on UNC path");
1987 /* existing tcon already has a reference */
1988 cifs_put_smb_ses(ses);
1989 if (tcon->seal != volume_info->seal)
1990 cERROR(1, "transport encryption setting "
1991 "conflicts with existing tid");
1992 return tcon;
1993 }
1994
1995 tcon = tconInfoAlloc();
1996 if (tcon == NULL) {
1997 rc = -ENOMEM;
1998 goto out_fail;
1999 }
2000
2001 tcon->ses = ses;
2002 if (volume_info->password) {
2003 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
2004 if (!tcon->password) {
2005 rc = -ENOMEM;
2006 goto out_fail;
2007 }
2008 }
2009
2010 if (strchr(volume_info->UNC + 3, '\\') == NULL
2011 && strchr(volume_info->UNC + 3, '/') == NULL) {
2012 cERROR(1, "Missing share name");
2013 rc = -ENODEV;
2014 goto out_fail;
2015 }
2016
2017 /* BB Do we need to wrap session_mutex around
2018 * this TCon call and Unix SetFS as
2019 * we do on SessSetup and reconnect? */
2020 xid = GetXid();
2021 rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls);
2022 FreeXid(xid);
2023 cFYI(1, "CIFS Tcon rc = %d", rc);
2024 if (rc)
2025 goto out_fail;
2026
2027 if (volume_info->nodfs) {
2028 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2029 cFYI(1, "DFS disabled (%d)", tcon->Flags);
2030 }
2031 tcon->seal = volume_info->seal;
2032 /* we can have only one retry value for a connection
2033 to a share so for resources mounted more than once
2034 to the same server share the last value passed in
2035 for the retry flag is used */
2036 tcon->retry = volume_info->retry;
2037 tcon->nocase = volume_info->nocase;
2038 tcon->local_lease = volume_info->local_lease;
2039
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302040 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002041 list_add(&tcon->tcon_list, &ses->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302042 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002043
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302044 cifs_fscache_get_super_cookie(tcon);
2045
Jeff Laytond00c28d2010-04-24 07:57:44 -04002046 return tcon;
2047
2048out_fail:
2049 tconInfoFree(tcon);
2050 return ERR_PTR(rc);
2051}
2052
Jeff Layton9d002df2010-10-06 19:51:11 -04002053void
2054cifs_put_tlink(struct tcon_link *tlink)
2055{
2056 if (!tlink || IS_ERR(tlink))
2057 return;
2058
2059 if (!atomic_dec_and_test(&tlink->tl_count) ||
2060 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
2061 tlink->tl_time = jiffies;
2062 return;
2063 }
2064
2065 if (!IS_ERR(tlink_tcon(tlink)))
2066 cifs_put_tcon(tlink_tcon(tlink));
2067 kfree(tlink);
2068 return;
2069}
Jeff Laytond00c28d2010-04-24 07:57:44 -04002070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071int
Steve French50c2f752007-07-13 00:33:32 +00002072get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
2073 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00002074 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 char *temp_unc;
2077 int rc = 0;
2078
2079 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00002080 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 if (pSesInfo->ipc_tid == 0) {
2083 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00002084 strnlen(pSesInfo->serverName,
2085 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 + 1 + 4 /* slash IPC$ */ + 2,
2087 GFP_KERNEL);
2088 if (temp_unc == NULL)
2089 return -ENOMEM;
2090 temp_unc[0] = '\\';
2091 temp_unc[1] = '\\';
2092 strcpy(temp_unc + 2, pSesInfo->serverName);
2093 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
2094 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002095 cFYI(1, "CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 kfree(temp_unc);
2097 }
2098 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00002099 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07002100 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00002101 /* BB map targetUNCs to dfs_info3 structures, here or
2102 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
2104 return rc;
2105}
2106
Jeff Layton09e50d52008-07-23 10:11:19 -04002107#ifdef CONFIG_DEBUG_LOCK_ALLOC
2108static struct lock_class_key cifs_key[2];
2109static struct lock_class_key cifs_slock_key[2];
2110
2111static inline void
2112cifs_reclassify_socket4(struct socket *sock)
2113{
2114 struct sock *sk = sock->sk;
2115 BUG_ON(sock_owned_by_user(sk));
2116 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2117 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2118}
2119
2120static inline void
2121cifs_reclassify_socket6(struct socket *sock)
2122{
2123 struct sock *sk = sock->sk;
2124 BUG_ON(sock_owned_by_user(sk));
2125 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2126 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2127}
2128#else
2129static inline void
2130cifs_reclassify_socket4(struct socket *sock)
2131{
2132}
2133
2134static inline void
2135cifs_reclassify_socket6(struct socket *sock)
2136{
2137}
2138#endif
2139
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002141static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142{
Steve French50c2f752007-07-13 00:33:32 +00002143 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Steve French50c2f752007-07-13 00:33:32 +00002145 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 /* mask a nibble at a time and encode */
2147 target[j] = 'A' + (0x0F & (source[i] >> 4));
2148 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002149 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 }
2151
2152}
2153
Ben Greear3eb9a882010-09-01 17:06:02 -07002154static int
2155bind_socket(struct TCP_Server_Info *server)
2156{
2157 int rc = 0;
2158 if (server->srcaddr.ss_family != AF_UNSPEC) {
2159 /* Bind to the specified local IP address */
2160 struct socket *socket = server->ssocket;
2161 rc = socket->ops->bind(socket,
2162 (struct sockaddr *) &server->srcaddr,
2163 sizeof(server->srcaddr));
2164 if (rc < 0) {
2165 struct sockaddr_in *saddr4;
2166 struct sockaddr_in6 *saddr6;
2167 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2168 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2169 if (saddr6->sin6_family == AF_INET6)
2170 cERROR(1, "cifs: "
2171 "Failed to bind to: %pI6c, error: %d\n",
2172 &saddr6->sin6_addr, rc);
2173 else
2174 cERROR(1, "cifs: "
2175 "Failed to bind to: %pI4, error: %d\n",
2176 &saddr4->sin_addr.s_addr, rc);
2177 }
2178 }
2179 return rc;
2180}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
2182static int
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002183ip_rfc1001_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184{
2185 int rc = 0;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002186 /*
2187 * some servers require RFC1001 sessinit before sending
2188 * negprot - BB check reconnection in case where second
2189 * sessinit is sent but no second negprot
2190 */
2191 struct rfc1002_session_packet *ses_init_buf;
2192 struct smb_hdr *smb_buf;
2193 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2194 GFP_KERNEL);
2195 if (ses_init_buf) {
2196 ses_init_buf->trailer.session_req.called_len = 32;
2197
2198 if (server->server_RFC1001_name &&
2199 server->server_RFC1001_name[0] != 0)
2200 rfc1002mangle(ses_init_buf->trailer.
2201 session_req.called_name,
2202 server->server_RFC1001_name,
2203 RFC1001_NAME_LEN_WITH_NULL);
2204 else
2205 rfc1002mangle(ses_init_buf->trailer.
2206 session_req.called_name,
2207 DEFAULT_CIFS_CALLED_NAME,
2208 RFC1001_NAME_LEN_WITH_NULL);
2209
2210 ses_init_buf->trailer.session_req.calling_len = 32;
2211
2212 /*
2213 * calling name ends in null (byte 16) from old smb
2214 * convention.
2215 */
2216 if (server->workstation_RFC1001_name &&
2217 server->workstation_RFC1001_name[0] != 0)
2218 rfc1002mangle(ses_init_buf->trailer.
2219 session_req.calling_name,
2220 server->workstation_RFC1001_name,
2221 RFC1001_NAME_LEN_WITH_NULL);
2222 else
2223 rfc1002mangle(ses_init_buf->trailer.
2224 session_req.calling_name,
2225 "LINUX_CIFS_CLNT",
2226 RFC1001_NAME_LEN_WITH_NULL);
2227
2228 ses_init_buf->trailer.session_req.scope1 = 0;
2229 ses_init_buf->trailer.session_req.scope2 = 0;
2230 smb_buf = (struct smb_hdr *)ses_init_buf;
2231
2232 /* sizeof RFC1002_SESSION_REQUEST with no scope */
2233 smb_buf->smb_buf_length = 0x81000044;
2234 rc = smb_send(server, smb_buf, 0x44);
2235 kfree(ses_init_buf);
2236 /*
2237 * RFC1001 layer in at least one server
2238 * requires very short break before negprot
2239 * presumably because not expecting negprot
2240 * to follow so fast. This is a simple
2241 * solution that works without
2242 * complicating the code and causes no
2243 * significant slowing down on mount
2244 * for everyone else
2245 */
2246 usleep_range(1000, 2000);
2247 }
2248 /*
2249 * else the negprot may still work without this
2250 * even though malloc failed
2251 */
2252
2253 return rc;
2254}
2255
2256static int
2257generic_ip_connect(struct TCP_Server_Info *server)
2258{
2259 int rc = 0;
2260 unsigned short int sport;
2261 int slen, sfamily;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002262 struct socket *socket = server->ssocket;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002263 struct sockaddr *saddr;
2264
2265 saddr = (struct sockaddr *) &server->dstaddr;
2266
2267 if (server->dstaddr.ss_family == AF_INET6) {
2268 sport = ((struct sockaddr_in6 *) saddr)->sin6_port;
2269 slen = sizeof(struct sockaddr_in6);
2270 sfamily = AF_INET6;
2271 } else {
2272 sport = ((struct sockaddr_in *) saddr)->sin_port;
2273 slen = sizeof(struct sockaddr_in);
2274 sfamily = AF_INET;
2275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002277 if (socket == NULL) {
Rob Landleyf1d0c992011-01-22 15:44:05 -06002278 rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
2279 IPPROTO_TCP, &socket, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002281 cERROR(1, "Error %d creating socket", rc);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002282 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002285
2286 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002287 cFYI(1, "Socket created");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002288 server->ssocket = socket;
2289 socket->sk->sk_allocation = GFP_NOFS;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002290 if (sfamily == AF_INET6)
2291 cifs_reclassify_socket6(socket);
2292 else
2293 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 }
2295
Ben Greear3eb9a882010-09-01 17:06:02 -07002296 rc = bind_socket(server);
2297 if (rc < 0)
2298 return rc;
2299
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002300 rc = socket->ops->connect(socket, saddr, slen, 0);
2301 if (rc < 0) {
2302 cFYI(1, "Error %d connecting to server", rc);
Jeff Laytond5c56052008-12-01 18:42:33 -05002303 sock_release(socket);
2304 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 return rc;
2306 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00002307
Jeff Laytond5c56052008-12-01 18:42:33 -05002308 /*
2309 * Eventually check for other socket options to change from
2310 * the default. sock_setsockopt not used because it expects
2311 * user space buffer
2312 */
2313 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002314 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002315
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002316 /* make the bufsizes depend on wsize/rsize and max requests */
2317 if (server->noautotune) {
2318 if (socket->sk->sk_sndbuf < (200 * 1024))
2319 socket->sk->sk_sndbuf = 200 * 1024;
2320 if (socket->sk->sk_rcvbuf < (140 * 1024))
2321 socket->sk->sk_rcvbuf = 140 * 1024;
2322 }
2323
Steve French6a5fa2362010-01-01 01:28:43 +00002324 if (server->tcp_nodelay) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002325 int val = 1;
Steve French6a5fa2362010-01-01 01:28:43 +00002326 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
2327 (char *)&val, sizeof(val));
2328 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002329 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00002330 }
2331
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002332 cFYI(1, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
2333 socket->sk->sk_sndbuf,
2334 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
2335
2336 if (sport == htons(RFC1001_PORT))
2337 rc = ip_rfc1001_connect(server);
Steve French50c2f752007-07-13 00:33:32 +00002338
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 return rc;
2340}
2341
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002342static int
2343ip_connect(struct TCP_Server_Info *server)
2344{
2345 unsigned short int *sport;
2346 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
2347 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2348
2349 if (server->dstaddr.ss_family == AF_INET6)
2350 sport = &addr6->sin6_port;
2351 else
2352 sport = &addr->sin_port;
2353
2354 if (*sport == 0) {
2355 int rc;
2356
2357 /* try with 445 port at first */
2358 *sport = htons(CIFS_PORT);
2359
2360 rc = generic_ip_connect(server);
2361 if (rc >= 0)
2362 return rc;
2363
2364 /* if it failed, try with 139 port */
2365 *sport = htons(RFC1001_PORT);
2366 }
2367
2368 return generic_ip_connect(server);
2369}
2370
Steve French50c2f752007-07-13 00:33:32 +00002371void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
2372 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00002373{
2374 /* if we are reconnecting then should we check to see if
2375 * any requested capabilities changed locally e.g. via
2376 * remount but we can not do much about it here
2377 * if they have (even if we could detect it by the following)
2378 * Perhaps we could add a backpointer to array of sb from tcon
2379 * or if we change to make all sb to same share the same
2380 * sb as NFS - then we only have one backpointer to sb.
2381 * What if we wanted to mount the server share twice once with
2382 * and once without posixacls or posix paths? */
2383 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002384
Steve Frenchc18c8422007-07-18 23:21:09 +00002385 if (vol_info && vol_info->no_linux_ext) {
2386 tcon->fsUnixInfo.Capability = 0;
2387 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002388 cFYI(1, "Linux protocol extensions disabled");
Steve Frenchc18c8422007-07-18 23:21:09 +00002389 return;
2390 } else if (vol_info)
2391 tcon->unix_ext = 1; /* Unix Extensions supported */
2392
2393 if (tcon->unix_ext == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002394 cFYI(1, "Unix extensions disabled so not set on reconnect");
Steve Frenchc18c8422007-07-18 23:21:09 +00002395 return;
2396 }
Steve French50c2f752007-07-13 00:33:32 +00002397
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002398 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002399 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002400
Steve French8af18972007-02-14 04:42:51 +00002401 /* check for reconnect case in which we do not
2402 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002403 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002404 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00002405 originally at mount time */
2406 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2407 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002408 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2409 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002410 cERROR(1, "POSIXPATH support change");
Steve French8af18972007-02-14 04:42:51 +00002411 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002412 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002413 cERROR(1, "possible reconnect error");
2414 cERROR(1, "server disabled POSIX path support");
Igor Mammedov11b6d642008-02-15 19:06:04 +00002415 }
Steve French8af18972007-02-14 04:42:51 +00002416 }
Steve French50c2f752007-07-13 00:33:32 +00002417
Steve French8af18972007-02-14 04:42:51 +00002418 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002419 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002420 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002421 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002422 cFYI(1, "negotiated posix acl support");
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002423 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002424 sb->s_flags |= MS_POSIXACL;
2425 }
2426
Steve French75865f8c2007-06-24 18:30:48 +00002427 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002428 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002429 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002430 cFYI(1, "negotiate posix pathnames");
Steve French75865f8c2007-06-24 18:30:48 +00002431 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002432 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002433 CIFS_MOUNT_POSIX_PATHS;
2434 }
Steve French50c2f752007-07-13 00:33:32 +00002435
Steve French984acfe2007-04-26 16:42:50 +00002436 /* We might be setting the path sep back to a different
2437 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002438 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002439 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002440 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002441
2442 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2443 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2444 CIFS_SB(sb)->rsize = 127 * 1024;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002445 cFYI(DBG2, "larger reads not supported by srv");
Steve French75865f8c2007-06-24 18:30:48 +00002446 }
2447 }
Steve French50c2f752007-07-13 00:33:32 +00002448
2449
Joe Perchesb6b38f72010-04-21 03:50:45 +00002450 cFYI(1, "Negotiate caps 0x%x", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00002451#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002452 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002453 cFYI(1, "FCNTL cap");
Steve French75865f8c2007-06-24 18:30:48 +00002454 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002455 cFYI(1, "EXTATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00002456 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002457 cFYI(1, "POSIX path cap");
Steve French75865f8c2007-06-24 18:30:48 +00002458 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002459 cFYI(1, "XATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00002460 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002461 cFYI(1, "POSIX ACL cap");
Steve French75865f8c2007-06-24 18:30:48 +00002462 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002463 cFYI(1, "very large read cap");
Steve French75865f8c2007-06-24 18:30:48 +00002464 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002465 cFYI(1, "very large write cap");
Steve French8af18972007-02-14 04:42:51 +00002466#endif /* CIFS_DEBUG2 */
2467 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002468 if (vol_info == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002469 cFYI(1, "resetting capabilities failed");
Steve French442aa312007-09-24 20:25:46 +00002470 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002471 cERROR(1, "Negotiating Unix capabilities "
Steve French5a44b312007-09-20 15:16:24 +00002472 "with the server failed. Consider "
2473 "mounting with the Unix Extensions\n"
2474 "disabled, if problems are found, "
2475 "by specifying the nounix mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00002476 "option.");
Steve French5a44b312007-09-20 15:16:24 +00002477
Steve French8af18972007-02-14 04:42:51 +00002478 }
2479 }
2480}
2481
Steve French03a143c2008-02-14 06:38:30 +00002482static void
2483convert_delimiter(char *path, char delim)
2484{
2485 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002486 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002487
2488 if (path == NULL)
2489 return;
2490
Steve French582d21e2008-05-13 04:54:12 +00002491 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002492 old_delim = '\\';
2493 else
2494 old_delim = '/';
2495
Steve French03a143c2008-02-14 06:38:30 +00002496 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002497 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002498 path[i] = delim;
2499 }
2500}
2501
Steve French3b795212008-11-13 19:45:32 +00002502static void setup_cifs_sb(struct smb_vol *pvolume_info,
2503 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002504{
Jeff Layton2de970f2010-10-06 19:51:12 -04002505 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
2506
Steve French3b795212008-11-13 19:45:32 +00002507 if (pvolume_info->rsize > CIFSMaxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002508 cERROR(1, "rsize %d too large, using MaxBufSize",
2509 pvolume_info->rsize);
Steve French3b795212008-11-13 19:45:32 +00002510 cifs_sb->rsize = CIFSMaxBufSize;
2511 } else if ((pvolume_info->rsize) &&
2512 (pvolume_info->rsize <= CIFSMaxBufSize))
2513 cifs_sb->rsize = pvolume_info->rsize;
2514 else /* default */
2515 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002516
Steve French3b795212008-11-13 19:45:32 +00002517 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002518 cERROR(1, "wsize %d too large, using 4096 instead",
2519 pvolume_info->wsize);
Steve French3b795212008-11-13 19:45:32 +00002520 cifs_sb->wsize = 4096;
2521 } else if (pvolume_info->wsize)
2522 cifs_sb->wsize = pvolume_info->wsize;
2523 else
2524 cifs_sb->wsize = min_t(const int,
2525 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2526 127*1024);
2527 /* old default of CIFSMaxBufSize was too small now
2528 that SMB Write2 can send multiple pages in kvec.
2529 RFC1001 does not describe what happens when frame
2530 bigger than 128K is sent so use that as max in
2531 conjunction with 52K kvec constraint on arch with 4K
2532 page size */
2533
2534 if (cifs_sb->rsize < 2048) {
2535 cifs_sb->rsize = 2048;
2536 /* Windows ME may prefer this */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002537 cFYI(1, "readsize set to minimum: 2048");
Steve French3b795212008-11-13 19:45:32 +00002538 }
2539 /* calculate prepath */
2540 cifs_sb->prepath = pvolume_info->prepath;
2541 if (cifs_sb->prepath) {
2542 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2543 /* we can not convert the / to \ in the path
2544 separators in the prefixpath yet because we do not
2545 know (until reset_cifs_unix_caps is called later)
2546 whether POSIX PATH CAP is available. We normalize
2547 the / to \ after reset_cifs_unix_caps is called */
2548 pvolume_info->prepath = NULL;
2549 } else
2550 cifs_sb->prepathlen = 0;
2551 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2552 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2553 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2554 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002555 cFYI(1, "file mode: 0x%x dir mode: 0x%x",
2556 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
Steve French3b795212008-11-13 19:45:32 +00002557
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05302558 cifs_sb->actimeo = pvolume_info->actimeo;
2559
Steve French3b795212008-11-13 19:45:32 +00002560 if (pvolume_info->noperm)
2561 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2562 if (pvolume_info->setuids)
2563 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2564 if (pvolume_info->server_ino)
2565 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2566 if (pvolume_info->remap)
2567 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2568 if (pvolume_info->no_xattr)
2569 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2570 if (pvolume_info->sfu_emul)
2571 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2572 if (pvolume_info->nobrl)
2573 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve Frenchbe652442009-02-23 15:21:59 +00002574 if (pvolume_info->nostrictsync)
Steve French4717bed2009-02-24 14:44:19 +00002575 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
Steve French13a6e422008-12-02 17:24:33 +00002576 if (pvolume_info->mand_lock)
2577 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002578 if (pvolume_info->cifs_acl)
2579 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2580 if (pvolume_info->override_uid)
2581 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2582 if (pvolume_info->override_gid)
2583 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2584 if (pvolume_info->dynperm)
2585 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05302586 if (pvolume_info->fsc)
2587 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
Jeff Layton0eb8a132010-10-06 19:51:12 -04002588 if (pvolume_info->multiuser)
2589 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
2590 CIFS_MOUNT_NO_PERM);
Pavel Shilovskyd39454f2011-01-24 14:16:35 -05002591 if (pvolume_info->strict_io)
2592 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
Steve French3b795212008-11-13 19:45:32 +00002593 if (pvolume_info->direct_io) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002594 cFYI(1, "mounting share using direct i/o");
Steve French3b795212008-11-13 19:45:32 +00002595 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2596 }
Stefan Metzmacher736a3322010-07-30 14:56:00 +02002597 if (pvolume_info->mfsymlinks) {
2598 if (pvolume_info->sfu_emul) {
2599 cERROR(1, "mount option mfsymlinks ignored if sfu "
2600 "mount option is used");
2601 } else {
2602 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
2603 }
2604 }
Steve French3b795212008-11-13 19:45:32 +00002605
2606 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
Joe Perchesb6b38f72010-04-21 03:50:45 +00002607 cERROR(1, "mount option dynperm ignored if cifsacl "
2608 "mount option supported");
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002609}
2610
Igor Mammedove4cce942009-02-10 14:10:26 +03002611static int
2612is_path_accessible(int xid, struct cifsTconInfo *tcon,
2613 struct cifs_sb_info *cifs_sb, const char *full_path)
2614{
2615 int rc;
Igor Mammedove4cce942009-02-10 14:10:26 +03002616 FILE_ALL_INFO *pfile_info;
2617
Igor Mammedove4cce942009-02-10 14:10:26 +03002618 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2619 if (pfile_info == NULL)
2620 return -ENOMEM;
2621
2622 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2623 0 /* not legacy */, cifs_sb->local_nls,
2624 cifs_sb->mnt_cifs_flags &
2625 CIFS_MOUNT_MAP_SPECIAL_CHR);
2626 kfree(pfile_info);
2627 return rc;
2628}
2629
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002630static void
2631cleanup_volume_info(struct smb_vol **pvolume_info)
2632{
2633 struct smb_vol *volume_info;
2634
Dan Carpenterad6cca62010-04-26 12:10:06 +02002635 if (!pvolume_info || !*pvolume_info)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002636 return;
2637
2638 volume_info = *pvolume_info;
2639 kzfree(volume_info->password);
2640 kfree(volume_info->UNC);
2641 kfree(volume_info->prepath);
2642 kfree(volume_info);
2643 *pvolume_info = NULL;
2644 return;
2645}
2646
Steve French2d6d5892009-04-09 00:36:44 +00002647#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002648/* build_path_to_root returns full path to root when
2649 * we do not have an exiting connection (tcon) */
2650static char *
2651build_unc_path_to_root(const struct smb_vol *volume_info,
2652 const struct cifs_sb_info *cifs_sb)
2653{
2654 char *full_path;
2655
2656 int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
2657 full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
2658 if (full_path == NULL)
2659 return ERR_PTR(-ENOMEM);
2660
2661 strncpy(full_path, volume_info->UNC, unc_len);
2662 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
2663 int i;
2664 for (i = 0; i < unc_len; i++) {
2665 if (full_path[i] == '\\')
2666 full_path[i] = '/';
2667 }
2668 }
2669
2670 if (cifs_sb->prepathlen)
2671 strncpy(full_path + unc_len, cifs_sb->prepath,
2672 cifs_sb->prepathlen);
2673
2674 full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
2675 return full_path;
2676}
Steve French2d6d5892009-04-09 00:36:44 +00002677#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679int
2680cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002681 char *mount_data_global, const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682{
Jeff Laytona2934c72009-12-03 08:09:41 -05002683 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002685 struct smb_vol *volume_info;
Jeff Laytona2934c72009-12-03 08:09:41 -05002686 struct cifsSesInfo *pSesInfo;
2687 struct cifsTconInfo *tcon;
2688 struct TCP_Server_Info *srvTcp;
Igor Mammedove4cce942009-02-10 14:10:26 +03002689 char *full_path;
Steve French2d6d5892009-04-09 00:36:44 +00002690 char *mount_data = mount_data_global;
Jeff Layton9d002df2010-10-06 19:51:11 -04002691 struct tcon_link *tlink;
Steve French2d6d5892009-04-09 00:36:44 +00002692#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002693 struct dfs_info3_param *referrals = NULL;
2694 unsigned int num_referrals = 0;
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002695 int referral_walks_count = 0;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002696try_mount_again:
Steve French2d6d5892009-04-09 00:36:44 +00002697#endif
Jeff Laytona2934c72009-12-03 08:09:41 -05002698 rc = 0;
2699 tcon = NULL;
2700 pSesInfo = NULL;
2701 srvTcp = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002702 full_path = NULL;
Jeff Layton9d002df2010-10-06 19:51:11 -04002703 tlink = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 xid = GetXid();
2706
Jeff Layton7586b762008-12-01 18:41:49 -05002707 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2708 if (!volume_info) {
2709 rc = -ENOMEM;
2710 goto out;
2711 }
Steve French50c2f752007-07-13 00:33:32 +00002712
Jeff Layton7586b762008-12-01 18:41:49 -05002713 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002714 rc = -EINVAL;
2715 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 }
2717
Jeff Layton7586b762008-12-01 18:41:49 -05002718 if (volume_info->nullauth) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002719 cFYI(1, "null user");
Jeff Layton7586b762008-12-01 18:41:49 -05002720 volume_info->username = "";
2721 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 /* BB fixme parse for domain name here */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002723 cFYI(1, "Username: %s", volume_info->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002725 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002726 /* In userspace mount helper we can get user name from alternate
2727 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002728 rc = -EINVAL;
2729 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 }
2731
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002733 if (volume_info->iocharset == NULL) {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002734 /* load_nls_default cannot return null */
2735 volume_info->local_nls = load_nls_default();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 } else {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002737 volume_info->local_nls = load_nls(volume_info->iocharset);
2738 if (volume_info->local_nls == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002739 cERROR(1, "CIFS mount error: iocharset %s not found",
2740 volume_info->iocharset);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002741 rc = -ELIBACC;
2742 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 }
2744 }
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002745 cifs_sb->local_nls = volume_info->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Jeff Layton63c038c2008-12-01 18:41:46 -05002747 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002748 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002749 if (IS_ERR(srvTcp)) {
2750 rc = PTR_ERR(srvTcp);
2751 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 }
2753
Jeff Layton36988c72010-04-24 07:57:43 -04002754 /* get a reference to a SMB session */
2755 pSesInfo = cifs_get_smb_ses(srvTcp, volume_info);
2756 if (IS_ERR(pSesInfo)) {
2757 rc = PTR_ERR(pSesInfo);
2758 pSesInfo = NULL;
2759 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
Steve French50c2f752007-07-13 00:33:32 +00002761
Jeff Laytond00c28d2010-04-24 07:57:44 -04002762 setup_cifs_sb(volume_info, cifs_sb);
2763 if (pSesInfo->capabilities & CAP_LARGE_FILES)
2764 sb->s_maxbytes = MAX_LFS_FILESIZE;
2765 else
2766 sb->s_maxbytes = MAX_NON_LFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Steve French8af18972007-02-14 04:42:51 +00002768 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 sb->s_time_gran = 100;
2770
Jeff Laytond00c28d2010-04-24 07:57:44 -04002771 /* search for existing tcon to this server share */
2772 tcon = cifs_get_tcon(pSesInfo, volume_info);
2773 if (IS_ERR(tcon)) {
2774 rc = PTR_ERR(tcon);
2775 tcon = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002776 goto remote_path_check;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002777 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002778
Steve Frenchd82c2df2008-11-15 00:07:26 +00002779 /* do not care if following two calls succeed - informational */
2780 if (!tcon->ipc) {
2781 CIFSSMBQFSDeviceInfo(xid, tcon);
2782 CIFSSMBQFSAttributeInfo(xid, tcon);
2783 }
2784
2785 /* tell server which Unix caps we support */
2786 if (tcon->ses->capabilities & CAP_UNIX)
2787 /* reset of caps checks mount to see if unix extensions
2788 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002789 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002790 else
2791 tcon->unix_ext = 0; /* server does not support them */
2792
2793 /* convert forward to back slashes in prepath here if needed */
2794 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2795 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2796
2797 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2798 cifs_sb->rsize = 1024 * 127;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002799 cFYI(DBG2, "no very large read support, rsize now 127K");
Steve Frenchd82c2df2008-11-15 00:07:26 +00002800 }
2801 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2802 cifs_sb->wsize = min(cifs_sb->wsize,
2803 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2804 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2805 cifs_sb->rsize = min(cifs_sb->rsize,
2806 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002808remote_path_check:
2809 /* check if a whole path (including prepath) is not remote */
2810 if (!rc && cifs_sb->prepathlen && tcon) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002811 /* build_path_to_root works only when we have a valid tcon */
Jeff Layton7d161b72010-12-07 02:10:35 -05002812 full_path = cifs_build_path_to_root(cifs_sb, tcon);
Igor Mammedove4cce942009-02-10 14:10:26 +03002813 if (full_path == NULL) {
2814 rc = -ENOMEM;
2815 goto mount_fail_check;
2816 }
2817 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
Jeff Layton03ceace2010-12-06 21:07:33 -05002818 if (rc != 0 && rc != -EREMOTE) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002819 kfree(full_path);
2820 goto mount_fail_check;
2821 }
2822 kfree(full_path);
2823 }
2824
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002825 /* get referral if needed */
2826 if (rc == -EREMOTE) {
Steve Frenchd036f502009-04-03 03:12:08 +00002827#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002828 if (referral_walks_count > MAX_NESTED_LINKS) {
2829 /*
2830 * BB: when we implement proper loop detection,
2831 * we will remove this check. But now we need it
2832 * to prevent an indefinite loop if 'DFS tree' is
2833 * misconfigured (i.e. has loops).
2834 */
2835 rc = -ELOOP;
2836 goto mount_fail_check;
2837 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002838 /* convert forward to back slashes in prepath here if needed */
2839 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2840 convert_delimiter(cifs_sb->prepath,
2841 CIFS_DIR_SEP(cifs_sb));
2842 full_path = build_unc_path_to_root(volume_info, cifs_sb);
2843 if (IS_ERR(full_path)) {
2844 rc = PTR_ERR(full_path);
2845 goto mount_fail_check;
2846 }
2847
Joe Perchesb6b38f72010-04-21 03:50:45 +00002848 cFYI(1, "Getting referral for: %s", full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002849 rc = get_dfs_path(xid, pSesInfo , full_path + 1,
2850 cifs_sb->local_nls, &num_referrals, &referrals,
2851 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
2852 if (!rc && num_referrals > 0) {
2853 char *fake_devname = NULL;
2854
2855 if (mount_data != mount_data_global)
2856 kfree(mount_data);
Jeff Layton7b91e262009-07-23 15:22:30 -04002857
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002858 mount_data = cifs_compose_mount_options(
2859 cifs_sb->mountdata, full_path + 1,
2860 referrals, &fake_devname);
Jeff Layton7b91e262009-07-23 15:22:30 -04002861
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002862 free_dfs_info_array(referrals, num_referrals);
Jeff Layton7b91e262009-07-23 15:22:30 -04002863 kfree(fake_devname);
2864 kfree(full_path);
2865
2866 if (IS_ERR(mount_data)) {
2867 rc = PTR_ERR(mount_data);
2868 mount_data = NULL;
2869 goto mount_fail_check;
2870 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002871
2872 if (tcon)
2873 cifs_put_tcon(tcon);
2874 else if (pSesInfo)
2875 cifs_put_smb_ses(pSesInfo);
2876
2877 cleanup_volume_info(&volume_info);
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002878 referral_walks_count++;
Jeff Laytona2934c72009-12-03 08:09:41 -05002879 FreeXid(xid);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002880 goto try_mount_again;
2881 }
Steve Frenchd036f502009-04-03 03:12:08 +00002882#else /* No DFS support, return error on mount */
2883 rc = -EOPNOTSUPP;
2884#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002885 }
2886
Jeff Layton9d002df2010-10-06 19:51:11 -04002887 if (rc)
2888 goto mount_fail_check;
2889
2890 /* now, hang the tcon off of the superblock */
2891 tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
2892 if (tlink == NULL) {
2893 rc = -ENOMEM;
2894 goto mount_fail_check;
2895 }
2896
Jeff Laytonb647c352010-10-28 11:16:44 -04002897 tlink->tl_uid = pSesInfo->linux_uid;
Jeff Layton9d002df2010-10-06 19:51:11 -04002898 tlink->tl_tcon = tcon;
2899 tlink->tl_time = jiffies;
2900 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2901 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2902
Jeff Layton413e6612010-10-28 13:33:38 -04002903 cifs_sb->master_tlink = tlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04002904 spin_lock(&cifs_sb->tlink_tree_lock);
2905 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
2906 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton413e6612010-10-28 13:33:38 -04002907
Jeff Layton2de970f2010-10-06 19:51:12 -04002908 queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
2909 TLINK_IDLE_EXPIRE);
2910
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002911mount_fail_check:
2912 /* on error free sesinfo and tcon struct if needed */
2913 if (rc) {
2914 if (mount_data != mount_data_global)
2915 kfree(mount_data);
2916 /* If find_unc succeeded then rc == 0 so we can not end */
2917 /* up accidently freeing someone elses tcon struct */
2918 if (tcon)
2919 cifs_put_tcon(tcon);
2920 else if (pSesInfo)
2921 cifs_put_smb_ses(pSesInfo);
2922 else
2923 cifs_put_tcp_session(srvTcp);
2924 goto out;
2925 }
2926
Jeff Layton7586b762008-12-01 18:41:49 -05002927 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 (in which case it is not needed anymore) but when new sesion is created
2929 the password ptr is put in the new session structure (in which case the
2930 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002931out:
2932 /* zero out password before freeing */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002933 cleanup_volume_info(&volume_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 FreeXid(xid);
2935 return rc;
2936}
2937
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938int
2939CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2940 const char *tree, struct cifsTconInfo *tcon,
2941 const struct nls_table *nls_codepage)
2942{
2943 struct smb_hdr *smb_buffer;
2944 struct smb_hdr *smb_buffer_response;
2945 TCONX_REQ *pSMB;
2946 TCONX_RSP *pSMBr;
2947 unsigned char *bcc_ptr;
2948 int rc = 0;
Jeff Layton690c5222011-01-20 13:36:51 -05002949 int length;
2950 __u16 bytes_left, count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
2952 if (ses == NULL)
2953 return -EIO;
2954
2955 smb_buffer = cifs_buf_get();
Steve Frenchca43e3b2009-09-01 17:20:50 +00002956 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 return -ENOMEM;
Steve Frenchca43e3b2009-09-01 17:20:50 +00002958
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 smb_buffer_response = smb_buffer;
2960
2961 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2962 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07002963
2964 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 smb_buffer->Uid = ses->Suid;
2966 pSMB = (TCONX_REQ *) smb_buffer;
2967 pSMBr = (TCONX_RSP *) smb_buffer_response;
2968
2969 pSMB->AndXCommand = 0xFF;
2970 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002972 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08002973 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00002974 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08002975 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00002976 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08002977 } else {
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06002978 pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08002979 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
2980 specified as required (when that support is added to
2981 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00002982 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08002983 by Samba (not sure whether other servers allow
2984 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00002985#ifdef CONFIG_CIFS_WEAK_PW_HASH
Jeff Layton04912d62010-04-24 07:57:45 -04002986 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05002987 (ses->server->secType == LANMAN))
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -05002988 calc_lanman_hash(tcon->password, ses->server->cryptkey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05002989 ses->server->secMode &
2990 SECMODE_PW_ENCRYPT ? true : false,
2991 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00002992 else
2993#endif /* CIFS_WEAK_PW_HASH */
Shirish Pargaonkaree2c9252011-01-27 09:58:04 -06002994 rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
2995 bcc_ptr);
Steve Frencheeac8042006-01-13 21:34:58 -08002996
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06002997 bcc_ptr += CIFS_AUTH_RESP_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002998 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00002999 /* must align unicode strings */
3000 *bcc_ptr = 0; /* null byte password */
3001 bcc_ptr++;
3002 }
Steve Frencheeac8042006-01-13 21:34:58 -08003003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
Steve French50c2f752007-07-13 00:33:32 +00003005 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003006 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3008
3009 if (ses->capabilities & CAP_STATUS32) {
3010 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3011 }
3012 if (ses->capabilities & CAP_DFS) {
3013 smb_buffer->Flags2 |= SMBFLG2_DFS;
3014 }
3015 if (ses->capabilities & CAP_UNICODE) {
3016 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3017 length =
Steve French50c2f752007-07-13 00:33:32 +00003018 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3019 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003020 (/* server len*/ + 256 /* share len */), nls_codepage);
3021 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 bcc_ptr += 2; /* skip trailing null */
3023 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 strcpy(bcc_ptr, tree);
3025 bcc_ptr += strlen(tree) + 1;
3026 }
3027 strcpy(bcc_ptr, "?????");
3028 bcc_ptr += strlen("?????");
3029 bcc_ptr += 1;
3030 count = bcc_ptr - &pSMB->Password[0];
3031 pSMB->hdr.smb_buf_length += count;
3032 pSMB->ByteCount = cpu_to_le16(count);
3033
Steve French133672e2007-11-13 22:41:37 +00003034 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
Jeff Layton77499812011-01-11 07:24:23 -05003035 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 /* above now done in SendReceive */
3038 if ((rc == 0) && (tcon != NULL)) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003039 bool is_unicode;
3040
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003042 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 tcon->tid = smb_buffer_response->Tid;
3044 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Layton690c5222011-01-20 13:36:51 -05003045 bytes_left = get_bcc(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003046 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003047 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3048 is_unicode = true;
3049 else
3050 is_unicode = false;
3051
Jeff Laytoncc20c032009-04-30 07:16:21 -04003052
Steve French50c2f752007-07-13 00:33:32 +00003053 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003054 if (length == 3) {
3055 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3056 (bcc_ptr[2] == 'C')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003057 cFYI(1, "IPC connection");
Steve French7f8ed422007-09-28 22:28:55 +00003058 tcon->ipc = 1;
3059 }
3060 } else if (length == 2) {
3061 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3062 /* the most common case */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003063 cFYI(1, "disk share connection");
Steve French7f8ed422007-09-28 22:28:55 +00003064 }
3065 }
Steve French50c2f752007-07-13 00:33:32 +00003066 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003067 bytes_left -= (length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003069
3070 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003071 kfree(tcon->nativeFileSystem);
Steve Frenchd185cda2009-04-30 17:45:10 +00003072 tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003073 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003074 nls_codepage);
3075
Joe Perchesb6b38f72010-04-21 03:50:45 +00003076 cFYI(1, "nativeFileSystem=%s", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003077
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003078 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003079 (smb_buffer_response->WordCount == 7))
3080 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003081 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3082 else
3083 tcon->Flags = 0;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003084 cFYI(1, "Tcon flags: 0x%x ", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003086 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 ses->ipc_tid = smb_buffer_response->Tid;
3088 }
3089
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003090 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 return rc;
3092}
3093
3094int
3095cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3096{
Jeff Laytonb647c352010-10-28 11:16:44 -04003097 struct rb_root *root = &cifs_sb->tlink_tree;
3098 struct rb_node *node;
3099 struct tcon_link *tlink;
Steve French50c2f752007-07-13 00:33:32 +00003100 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
Jeff Layton2de970f2010-10-06 19:51:12 -04003102 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3103
Jeff Laytonb647c352010-10-28 11:16:44 -04003104 spin_lock(&cifs_sb->tlink_tree_lock);
3105 while ((node = rb_first(root))) {
3106 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3107 cifs_get_tlink(tlink);
3108 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3109 rb_erase(node, root);
Steve French50c2f752007-07-13 00:33:32 +00003110
Jeff Laytonb647c352010-10-28 11:16:44 -04003111 spin_unlock(&cifs_sb->tlink_tree_lock);
3112 cifs_put_tlink(tlink);
3113 spin_lock(&cifs_sb->tlink_tree_lock);
3114 }
3115 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003116
Steve French2fe87f02006-09-21 07:02:52 +00003117 tmp = cifs_sb->prepath;
3118 cifs_sb->prepathlen = 0;
3119 cifs_sb->prepath = NULL;
3120 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
Jeff Layton9d002df2010-10-06 19:51:11 -04003122 return 0;
Steve French50c2f752007-07-13 00:33:32 +00003123}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
Jeff Layton198b5682010-04-24 07:57:48 -04003125int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126{
3127 int rc = 0;
Jeff Layton198b5682010-04-24 07:57:48 -04003128 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129
Jeff Layton198b5682010-04-24 07:57:48 -04003130 /* only send once per connect */
3131 if (server->maxBuf != 0)
3132 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
Jeff Layton198b5682010-04-24 07:57:48 -04003134 rc = CIFSSMBNegotiate(xid, ses);
3135 if (rc == -EAGAIN) {
3136 /* retry only once on 1st time connection */
3137 rc = CIFSSMBNegotiate(xid, ses);
3138 if (rc == -EAGAIN)
3139 rc = -EHOSTDOWN;
3140 }
3141 if (rc == 0) {
3142 spin_lock(&GlobalMid_Lock);
3143 if (server->tcpStatus != CifsExiting)
3144 server->tcpStatus = CifsGood;
3145 else
3146 rc = -EHOSTDOWN;
3147 spin_unlock(&GlobalMid_Lock);
3148
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 }
Steve French26b994f2008-08-06 05:11:33 +00003150
Jeff Layton198b5682010-04-24 07:57:48 -04003151 return rc;
3152}
Steve French26b994f2008-08-06 05:11:33 +00003153
Jeff Layton198b5682010-04-24 07:57:48 -04003154
3155int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
3156 struct nls_table *nls_info)
3157{
3158 int rc = 0;
3159 struct TCP_Server_Info *server = ses->server;
3160
3161 ses->flags = 0;
3162 ses->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003163 if (linuxExtEnabled == 0)
Jeff Layton198b5682010-04-24 07:57:48 -04003164 ses->capabilities &= (~CAP_UNIX);
Steve French20418ac2009-04-30 16:13:32 +00003165
Joe Perchesb6b38f72010-04-21 03:50:45 +00003166 cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
3167 server->secMode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003168
Jeff Layton198b5682010-04-24 07:57:48 -04003169 rc = CIFS_SessSetup(xid, ses, nls_info);
Steve French26b994f2008-08-06 05:11:33 +00003170 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003171 cERROR(1, "Send error in SessSetup = %d", rc);
Steve French26b994f2008-08-06 05:11:33 +00003172 } else {
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003173 mutex_lock(&ses->server->srv_mutex);
3174 if (!server->session_estab) {
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003175 server->session_key.response = ses->auth_key.response;
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003176 server->session_key.len = ses->auth_key.len;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003177 server->sequence_number = 0x2;
3178 server->session_estab = true;
3179 ses->auth_key.response = NULL;
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003180 }
3181 mutex_unlock(&server->srv_mutex);
3182
Joe Perchesb6b38f72010-04-21 03:50:45 +00003183 cFYI(1, "CIFS Session Established successfully");
Steve French20418ac2009-04-30 16:13:32 +00003184 spin_lock(&GlobalMid_Lock);
Jeff Layton198b5682010-04-24 07:57:48 -04003185 ses->status = CifsGood;
3186 ses->need_reconnect = false;
Steve French20418ac2009-04-30 16:13:32 +00003187 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003188 }
3189
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003190 kfree(ses->auth_key.response);
3191 ses->auth_key.response = NULL;
3192 ses->auth_key.len = 0;
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05003193 kfree(ses->ntlmssp);
3194 ses->ntlmssp = NULL;
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003195
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 return rc;
3197}
3198
Steve Frenchd2445552010-10-08 03:38:46 +00003199static struct cifsTconInfo *
Jeff Layton9d002df2010-10-06 19:51:11 -04003200cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
3201{
3202 struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
3203 struct cifsSesInfo *ses;
3204 struct cifsTconInfo *tcon = NULL;
3205 struct smb_vol *vol_info;
3206 char username[MAX_USERNAME_SIZE + 1];
3207
3208 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
3209 if (vol_info == NULL) {
3210 tcon = ERR_PTR(-ENOMEM);
3211 goto out;
3212 }
3213
3214 snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
3215 vol_info->username = username;
3216 vol_info->local_nls = cifs_sb->local_nls;
3217 vol_info->linux_uid = fsuid;
3218 vol_info->cred_uid = fsuid;
3219 vol_info->UNC = master_tcon->treeName;
3220 vol_info->retry = master_tcon->retry;
3221 vol_info->nocase = master_tcon->nocase;
3222 vol_info->local_lease = master_tcon->local_lease;
3223 vol_info->no_linux_ext = !master_tcon->unix_ext;
3224
3225 /* FIXME: allow for other secFlg settings */
3226 vol_info->secFlg = CIFSSEC_MUST_KRB5;
3227
3228 /* get a reference for the same TCP session */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303229 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003230 ++master_tcon->ses->server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303231 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003232
3233 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
3234 if (IS_ERR(ses)) {
3235 tcon = (struct cifsTconInfo *)ses;
3236 cifs_put_tcp_session(master_tcon->ses->server);
3237 goto out;
3238 }
3239
3240 tcon = cifs_get_tcon(ses, vol_info);
3241 if (IS_ERR(tcon)) {
3242 cifs_put_smb_ses(ses);
3243 goto out;
3244 }
3245
3246 if (ses->capabilities & CAP_UNIX)
3247 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
3248out:
3249 kfree(vol_info);
3250
3251 return tcon;
3252}
3253
Jeff Layton413e6612010-10-28 13:33:38 -04003254static inline struct tcon_link *
Jeff Layton9d002df2010-10-06 19:51:11 -04003255cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
3256{
Jeff Layton413e6612010-10-28 13:33:38 -04003257 return cifs_sb->master_tlink;
Jeff Layton9d002df2010-10-06 19:51:11 -04003258}
3259
3260struct cifsTconInfo *
3261cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3262{
3263 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3264}
3265
3266static int
3267cifs_sb_tcon_pending_wait(void *unused)
3268{
3269 schedule();
3270 return signal_pending(current) ? -ERESTARTSYS : 0;
3271}
3272
Jeff Laytonb647c352010-10-28 11:16:44 -04003273/* find and return a tlink with given uid */
3274static struct tcon_link *
3275tlink_rb_search(struct rb_root *root, uid_t uid)
3276{
3277 struct rb_node *node = root->rb_node;
3278 struct tcon_link *tlink;
3279
3280 while (node) {
3281 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3282
3283 if (tlink->tl_uid > uid)
3284 node = node->rb_left;
3285 else if (tlink->tl_uid < uid)
3286 node = node->rb_right;
3287 else
3288 return tlink;
3289 }
3290 return NULL;
3291}
3292
3293/* insert a tcon_link into the tree */
3294static void
3295tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
3296{
3297 struct rb_node **new = &(root->rb_node), *parent = NULL;
3298 struct tcon_link *tlink;
3299
3300 while (*new) {
3301 tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
3302 parent = *new;
3303
3304 if (tlink->tl_uid > new_tlink->tl_uid)
3305 new = &((*new)->rb_left);
3306 else
3307 new = &((*new)->rb_right);
3308 }
3309
3310 rb_link_node(&new_tlink->tl_rbnode, parent, new);
3311 rb_insert_color(&new_tlink->tl_rbnode, root);
3312}
3313
Jeff Layton9d002df2010-10-06 19:51:11 -04003314/*
3315 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3316 * current task.
3317 *
3318 * If the superblock doesn't refer to a multiuser mount, then just return
3319 * the master tcon for the mount.
3320 *
Suresh Jayaraman6ef933a2010-11-03 10:53:49 +05303321 * First, search the rbtree for an existing tcon for this fsuid. If one
Jeff Layton9d002df2010-10-06 19:51:11 -04003322 * exists, then check to see if it's pending construction. If it is then wait
3323 * for construction to complete. Once it's no longer pending, check to see if
3324 * it failed and either return an error or retry construction, depending on
3325 * the timeout.
3326 *
3327 * If one doesn't exist then insert a new tcon_link struct into the tree and
3328 * try to construct a new one.
3329 */
3330struct tcon_link *
3331cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
3332{
3333 int ret;
Jeff Laytonb647c352010-10-28 11:16:44 -04003334 uid_t fsuid = current_fsuid();
Jeff Layton9d002df2010-10-06 19:51:11 -04003335 struct tcon_link *tlink, *newtlink;
3336
3337 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
3338 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3339
3340 spin_lock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04003341 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04003342 if (tlink)
3343 cifs_get_tlink(tlink);
3344 spin_unlock(&cifs_sb->tlink_tree_lock);
3345
3346 if (tlink == NULL) {
3347 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
3348 if (newtlink == NULL)
3349 return ERR_PTR(-ENOMEM);
Jeff Laytonb647c352010-10-28 11:16:44 -04003350 newtlink->tl_uid = fsuid;
Jeff Layton9d002df2010-10-06 19:51:11 -04003351 newtlink->tl_tcon = ERR_PTR(-EACCES);
3352 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
3353 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
3354 cifs_get_tlink(newtlink);
3355
Jeff Layton9d002df2010-10-06 19:51:11 -04003356 spin_lock(&cifs_sb->tlink_tree_lock);
3357 /* was one inserted after previous search? */
Jeff Laytonb647c352010-10-28 11:16:44 -04003358 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04003359 if (tlink) {
3360 cifs_get_tlink(tlink);
3361 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003362 kfree(newtlink);
3363 goto wait_for_construction;
3364 }
Jeff Layton9d002df2010-10-06 19:51:11 -04003365 tlink = newtlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04003366 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
3367 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003368 } else {
3369wait_for_construction:
3370 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
3371 cifs_sb_tcon_pending_wait,
3372 TASK_INTERRUPTIBLE);
3373 if (ret) {
3374 cifs_put_tlink(tlink);
3375 return ERR_PTR(ret);
3376 }
3377
3378 /* if it's good, return it */
3379 if (!IS_ERR(tlink->tl_tcon))
3380 return tlink;
3381
3382 /* return error if we tried this already recently */
3383 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
3384 cifs_put_tlink(tlink);
3385 return ERR_PTR(-EACCES);
3386 }
3387
3388 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
3389 goto wait_for_construction;
3390 }
3391
3392 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
3393 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
3394 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
3395
3396 if (IS_ERR(tlink->tl_tcon)) {
3397 cifs_put_tlink(tlink);
3398 return ERR_PTR(-EACCES);
3399 }
3400
3401 return tlink;
3402}
Jeff Layton2de970f2010-10-06 19:51:12 -04003403
3404/*
3405 * periodic workqueue job that scans tcon_tree for a superblock and closes
3406 * out tcons.
3407 */
3408static void
3409cifs_prune_tlinks(struct work_struct *work)
3410{
3411 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
3412 prune_tlinks.work);
Jeff Laytonb647c352010-10-28 11:16:44 -04003413 struct rb_root *root = &cifs_sb->tlink_tree;
3414 struct rb_node *node = rb_first(root);
3415 struct rb_node *tmp;
3416 struct tcon_link *tlink;
Jeff Layton2de970f2010-10-06 19:51:12 -04003417
Jeff Laytonb647c352010-10-28 11:16:44 -04003418 /*
3419 * Because we drop the spinlock in the loop in order to put the tlink
3420 * it's not guarded against removal of links from the tree. The only
3421 * places that remove entries from the tree are this function and
3422 * umounts. Because this function is non-reentrant and is canceled
3423 * before umount can proceed, this is safe.
3424 */
3425 spin_lock(&cifs_sb->tlink_tree_lock);
3426 node = rb_first(root);
3427 while (node != NULL) {
3428 tmp = node;
3429 node = rb_next(tmp);
3430 tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
3431
3432 if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
3433 atomic_read(&tlink->tl_count) != 0 ||
3434 time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
3435 continue;
3436
3437 cifs_get_tlink(tlink);
3438 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3439 rb_erase(tmp, root);
3440
Jeff Layton2de970f2010-10-06 19:51:12 -04003441 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04003442 cifs_put_tlink(tlink);
3443 spin_lock(&cifs_sb->tlink_tree_lock);
3444 }
3445 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton2de970f2010-10-06 19:51:12 -04003446
3447 queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
3448 TLINK_IDLE_EXPIRE);
3449}