blob: 019f00380d129b82aee0645323af10412a4cf28e [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070055extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
56 unsigned char *p24);
57
58extern 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 */
67 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070068 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
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;
Steve French95b1cb92008-05-15 16:44:38 +000087 bool remap:1; /* set to remap seven reserved chars in filenames */
88 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000089 bool no_linux_ext:1;
90 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000091 bool nullauth:1; /* attempt to authenticate with null user */
92 bool nocase:1; /* request case insensitive filenames */
93 bool nobrl:1; /* disable sending byte range locks to srv */
Steve French13a6e422008-12-02 17:24:33 +000094 bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
Steve French95b1cb92008-05-15 16:44:38 +000095 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000096 bool nodfs:1; /* Do not request DFS, even if available */
97 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000098 bool noblocksnd:1;
99 bool noautotune:1;
Steve Frenchbe652442009-02-23 15:21:59 +0000100 bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
Suresh Jayaramanfa1df752010-07-05 18:13:36 +0530101 bool fsc:1; /* enable fscache */
Stefan Metzmacher736a3322010-07-30 14:56:00 +0200102 bool mfsymlinks:1; /* use Minshall+French Symlinks */
Jeff Layton0eb8a132010-10-06 19:51:12 -0400103 bool multiuser:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 unsigned int rsize;
105 unsigned int wsize;
Steve French6a5fa2362010-01-01 01:28:43 +0000106 bool sockopt_tcp_nodelay:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000108 char *prepath;
Ben Greear3eb9a882010-09-01 17:06:02 -0700109 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
Jeff Laytona5fc4ce2010-04-24 07:57:42 -0400110 struct nls_table *local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
Jeff Layton2de970f2010-10-06 19:51:12 -0400113/* FIXME: should these be tunable? */
Jeff Layton9d002df2010-10-06 19:51:11 -0400114#define TLINK_ERROR_EXPIRE (1 * HZ)
Jeff Layton2de970f2010-10-06 19:51:12 -0400115#define TLINK_IDLE_EXPIRE (600 * HZ)
Jeff Layton9d002df2010-10-06 19:51:11 -0400116
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500117static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500118static int ipv6_connect(struct TCP_Server_Info *server);
Jeff Layton2de970f2010-10-06 19:51:12 -0400119static void cifs_prune_tlinks(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Jeff Laytond5c56052008-12-01 18:42:33 -0500121/*
122 * cifs tcp session reconnection
123 *
124 * mark tcp session as reconnecting so temporarily locked
125 * mark all smb sessions as reconnecting for tcp session
126 * reconnect tcp session
127 * wake up waiters on reconnection? - (not needed currently)
128 */
Steve French2cd646a2006-09-28 19:43:08 +0000129static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130cifs_reconnect(struct TCP_Server_Info *server)
131{
132 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500133 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct cifsSesInfo *ses;
135 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000136 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000139 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000140 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 next time through the loop */
142 spin_unlock(&GlobalMid_Lock);
143 return rc;
144 } else
145 server->tcpStatus = CifsNeedReconnect;
146 spin_unlock(&GlobalMid_Lock);
147 server->maxBuf = 0;
148
Joe Perchesb6b38f72010-04-21 03:50:45 +0000149 cFYI(1, "Reconnecting tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 /* before reconnecting the tcp session, mark the smb session (uid)
152 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500153 read_lock(&cifs_tcp_ses_lock);
154 list_for_each(tmp, &server->smb_ses_list) {
155 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
156 ses->need_reconnect = true;
157 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500158 list_for_each(tmp2, &ses->tcon_list) {
159 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
160 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500163 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500165 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000166 if (server->ssocket) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000167 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
168 server->ssocket->flags);
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800169 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000170 cFYI(1, "Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000171 server->ssocket->state,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000172 server->ssocket->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 sock_release(server->ssocket);
174 server->ssocket = NULL;
175 }
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -0500176 server->sequence_number = 0;
177 server->session_estab = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 spin_lock(&GlobalMid_Lock);
180 list_for_each(tmp, &server->pending_mid_q) {
181 mid_entry = list_entry(tmp, struct
182 mid_q_entry,
183 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000184 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700185 /* Mark other intransit requests as needing
186 retry so we do not immediately mark the
187 session bad again (ie after we reconnect
188 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000189 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
191 }
192 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500193 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Jeff Layton469ee612008-10-16 18:46:39 +0000195 while ((server->tcpStatus != CifsExiting) &&
196 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000197 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500198 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500199 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500200 else
201 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000202 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000203 cFYI(1, "reconnect error %d", rc);
Steve French0cb766a2005-04-28 22:41:11 -0700204 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 } else {
206 atomic_inc(&tcpSesReconnectCount);
207 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000208 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 server->tcpStatus = CifsGood;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000210 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* atomic_set(&server->inFlight,0);*/
212 wake_up(&server->response_q);
213 }
214 }
215 return rc;
216}
217
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700219 return codes:
220 0 not a transact2, or all data present
221 >0 transact2 with that much data missing
222 -EINVAL = invalid transact2
223
224 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000225static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700226{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000227 struct smb_t2_rsp *pSMBt;
228 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700229 int data_in_this_rsp;
230 int remaining;
231
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700233 return 0;
234
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000235 /* check for plausible wct, bcc and t2 data and parm sizes */
236 /* check for parm and data offset going beyond end of smb */
237 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000238 cFYI(1, "invalid transact2 word count");
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 return -EINVAL;
240 }
241
242 pSMBt = (struct smb_t2_rsp *)pSMB;
243
244 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
245 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
246
247 remaining = total_data_size - data_in_this_rsp;
248
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000249 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000251 else if (remaining < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000252 cFYI(1, "total data %d smaller than data in frame %d",
253 total_data_size, data_in_this_rsp);
Steve Frenche4eb2952005-04-28 22:41:09 -0700254 return -EINVAL;
255 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000256 cFYI(1, "missing %d bytes from transact2, check next response",
257 remaining);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000258 if (total_data_size > maxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000259 cERROR(1, "TotalDataSize %d is over maximum buffer %d",
260 total_data_size, maxBufSize);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000261 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700262 }
263 return remaining;
264 }
265}
266
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000267static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700268{
269 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
270 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
271 int total_data_size;
272 int total_in_buf;
273 int remaining;
274 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 char *data_area_of_target;
276 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700277 __u16 byte_count;
278
279 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
280
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000282 cFYI(1, "total data size of primary and secondary t2 differ");
Steve Frenche4eb2952005-04-28 22:41:09 -0700283 }
284
285 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
286
287 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000288
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000289 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700290 return -EINVAL;
291
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700293 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000294
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000296 if (remaining < total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000297 cFYI(1, "transact2 2nd response contains too much data");
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 }
299
300 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000301 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700302 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
303 /* validate target area */
304
305 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700307
308 data_area_of_target += total_in_buf;
309
310 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700312 total_in_buf += total_in_buf2;
313 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
314 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
315 byte_count += total_in_buf2;
316 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
317
Steve French70ca7342005-09-22 16:32:06 -0700318 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700319 byte_count += total_in_buf2;
320
321 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000322
Steve French70ca7342005-09-22 16:32:06 -0700323 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700324
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000325 if (remaining == total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000326 cFYI(1, "found the last secondary response");
Steve Frenche4eb2952005-04-28 22:41:09 -0700327 return 0; /* we are done */
328 } else /* more responses to go */
329 return 1;
330
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333static int
334cifs_demultiplex_thread(struct TCP_Server_Info *server)
335{
336 int length;
337 unsigned int pdu_length, total_read;
338 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700339 struct smb_hdr *bigbuf = NULL;
340 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 struct msghdr smb_msg;
342 struct kvec iov;
343 struct socket *csocket = server->ssocket;
344 struct list_head *tmp;
345 struct cifsSesInfo *ses;
346 struct task_struct *task_to_wake = NULL;
347 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700348 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000349 bool isLargeBuf = false;
350 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700351 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 current->flags |= PF_MEMALLOC;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000354 cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400355
356 length = atomic_inc_return(&tcpSesAllocCount);
357 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000358 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
359 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700361 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000362 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700363 if (try_to_freeze())
364 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700365 if (bigbuf == NULL) {
366 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000367 if (!bigbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000368 cERROR(1, "No memory for large SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 msleep(3000);
370 /* retry will check if exiting */
371 continue;
372 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000373 } else if (isLargeBuf) {
374 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000375 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700377
378 if (smallbuf == NULL) {
379 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000380 if (!smallbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000381 cERROR(1, "No memory for SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700382 msleep(1000);
383 /* retry will check if exiting */
384 continue;
385 }
386 /* beginning of smb buffer is cleared in our buf_get */
387 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000388 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700389
Steve French4b18f2a2008-04-29 00:06:05 +0000390 isLargeBuf = false;
391 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 iov.iov_base = smb_buffer;
394 iov.iov_len = 4;
395 smb_msg.msg_control = NULL;
396 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000397 pdu_length = 4; /* enough to get RFC1001 header */
398incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 length =
400 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000401 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Jeff Layton469ee612008-10-16 18:46:39 +0000403 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 } else if (server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000406 cFYI(1, "Reconnect after server stopped responding");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 cifs_reconnect(server);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000408 cFYI(1, "call to reconnect done");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 csocket = server->ssocket;
410 continue;
Jeff Layton522bbe62010-09-03 12:00:49 -0400411 } else if (length == -ERESTARTSYS ||
412 length == -EAGAIN ||
413 length == -EINTR) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700414 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 allowing socket to clear and app threads to set
416 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000417 if (pdu_length < 4) {
418 iov.iov_base = (4 - pdu_length) +
419 (char *)smb_buffer;
420 iov.iov_len = pdu_length;
421 smb_msg.msg_control = NULL;
422 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000423 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000424 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000425 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000427 cFYI(1, "Reconnect after unexpected peek error %d",
428 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 cifs_reconnect(server);
430 csocket = server->ssocket;
431 wake_up(&server->response_q);
432 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000433 } else if (length < pdu_length) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000434 cFYI(1, "requested %d bytes but only got %d bytes",
435 pdu_length, length);
Steve Frenchf01d5e12007-08-30 21:13:31 +0000436 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000437 msleep(1);
438 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
Steve French67010fb2005-04-28 22:41:09 -0700440
Steve French70ca7342005-09-22 16:32:06 -0700441 /* The right amount was read from socket - 4 bytes */
442 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700443
Steve French70ca7342005-09-22 16:32:06 -0700444 /* the first byte big endian of the length field,
445 is actually not part of the length but the type
446 with the most common, zero, as regular data */
447 temp = *((char *) smb_buffer);
448
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000449 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700450 but we convert it here so it is always manipulated
451 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700452 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700453 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700454
Joe Perchesb6b38f72010-04-21 03:50:45 +0000455 cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
Steve French70ca7342005-09-22 16:32:06 -0700456
457 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000458 continue;
Steve French70ca7342005-09-22 16:32:06 -0700459 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000460 cFYI(1, "Good RFC 1002 session rsp");
Steve Frenche4eb2952005-04-28 22:41:09 -0700461 continue;
Steve French70ca7342005-09-22 16:32:06 -0700462 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700464 an error on SMB negprot response */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000465 cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
466 pdu_length);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400467 /* give server a second to clean up */
468 msleep(1000);
469 /* always try 445 first on reconnect since we get NACK
470 * on some if we ever connected to port 139 (the NACK
471 * is since we do not begin with RFC1001 session
472 * initialize frame)
473 */
Jeff Layton32670392010-09-03 12:00:50 -0400474 cifs_set_port((struct sockaddr *)
475 &server->addr.sockAddr, CIFS_PORT);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400476 cifs_reconnect(server);
477 csocket = server->ssocket;
478 wake_up(&server->response_q);
479 continue;
Steve French70ca7342005-09-22 16:32:06 -0700480 } else if (temp != (char) 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cERROR(1, "Unknown RFC 1002 frame");
Steve French70ca7342005-09-22 16:32:06 -0700482 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
483 length);
Steve French46810cb2005-04-28 22:41:09 -0700484 cifs_reconnect(server);
485 csocket = server->ssocket;
486 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700487 }
488
489 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000490 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000491 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 cERROR(1, "Invalid size SMB length %d pdu_length %d",
493 length, pdu_length+4);
Steve Frenche4eb2952005-04-28 22:41:09 -0700494 cifs_reconnect(server);
495 csocket = server->ssocket;
496 wake_up(&server->response_q);
497 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000498 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700499
500 /* else length ok */
501 reconnect = 0;
502
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000504 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 memcpy(bigbuf, smallbuf, 4);
506 smb_buffer = bigbuf;
507 }
508 length = 0;
509 iov.iov_base = 4 + (char *)smb_buffer;
510 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 total_read += length) {
513 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
514 pdu_length - total_read, 0);
Jeff Layton522bbe62010-09-03 12:00:49 -0400515 if (server->tcpStatus == CifsExiting) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700516 /* then will exit */
517 reconnect = 2;
518 break;
519 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700520 cifs_reconnect(server);
521 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000522 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 /* Now we will reread sock */
524 reconnect = 1;
525 break;
Jeff Layton522bbe62010-09-03 12:00:49 -0400526 } else if (length == -ERESTARTSYS ||
527 length == -EAGAIN ||
528 length == -EINTR) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 threads to set tcpStatus
532 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000533 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700534 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000536 cERROR(1, "Received no data, expecting %d",
537 pdu_length - total_read);
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 cifs_reconnect(server);
539 csocket = server->ssocket;
540 reconnect = 1;
541 break;
Steve French46810cb2005-04-28 22:41:09 -0700542 }
543 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000544 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000546 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 continue;
548
549 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000550
Steve Frenche4eb2952005-04-28 22:41:09 -0700551
552 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000553 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700554 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700555 continue;
556 }
557
558
559 task_to_wake = NULL;
560 spin_lock(&GlobalMid_Lock);
561 list_for_each(tmp, &server->pending_mid_q) {
562 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
563
Steve French50c2f752007-07-13 00:33:32 +0000564 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
566 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000567 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000569 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000570 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000572 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700573 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000574 mid_entry->multiRsp =
575 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700576 break;
577 } else {
578 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000579 mid_entry->multiEnd =
580 true;
Steve French50c2f752007-07-13 00:33:32 +0000581 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 }
583 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000584 if (!isLargeBuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000585 cERROR(1, "1st trans2 resp needs bigbuf");
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000587 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700588 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700589 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700590 mid_entry->resp_buf =
591 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000592 mid_entry->largeBuf =
593 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 bigbuf = NULL;
595 }
596 }
597 break;
Steve French50c2f752007-07-13 00:33:32 +0000598 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000600 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700601multi_t2_fnd:
602 task_to_wake = mid_entry->tsk;
603 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700604#ifdef CONFIG_CIFS_STATS2
605 mid_entry->when_received = jiffies;
606#endif
Steve French3a5ff612006-07-14 22:37:11 +0000607 /* so we do not time out requests to server
608 which is still responding (since server could
609 be busy but not dead) */
610 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700611 break;
612 }
613 }
614 spin_unlock(&GlobalMid_Lock);
615 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700616 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000617 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700618 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000619 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700620 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000621 else
Steve Frenchcd634992005-04-28 22:41:10 -0700622 smallbuf = NULL;
623 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700624 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000625 } else if (!is_valid_oplock_break(smb_buffer, server) &&
626 !isMultiRsp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cERROR(1, "No task to wake, unknown frame received! "
628 "NumMids %d", midCount.counter);
Steve French50c2f752007-07-13 00:33:32 +0000629 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700630 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000631#ifdef CONFIG_CIFS_DEBUG2
632 cifs_dump_detail(smb_buffer);
633 cifs_dump_mids(server);
634#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000635
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 }
637 } /* end while !EXITING */
638
Jeff Laytone7ddee92008-11-14 13:44:38 -0500639 /* take it off the list, if it's not already */
640 write_lock(&cifs_tcp_ses_lock);
641 list_del_init(&server->tcp_ses_list);
642 write_unlock(&cifs_tcp_ses_lock);
643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 spin_lock(&GlobalMid_Lock);
645 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000646 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000647 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000648
Steve French31ca3bc2005-04-28 22:41:11 -0700649 /* check if we have blocked requests that need to free */
650 /* Note that cifs_max_pending is normally 50, but
651 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000652 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000653 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700654 atomic_set(&server->inFlight, cifs_max_pending - 1);
655 /* We do not want to set the max_pending too low or we
656 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000658 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700660 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 to the same server - they now will see the session is in exit state
662 and get out of SendReceive. */
663 wake_up_all(&server->request_q);
664 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700665 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000666
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000667 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 sock_release(csocket);
669 server->ssocket = NULL;
670 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700671 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000672 cifs_buf_release(bigbuf);
673 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700674 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Jeff Layton14fbf502008-11-14 13:53:46 -0500676 /*
677 * BB: we shouldn't have to do any of this. It shouldn't be
678 * possible to exit from the thread with active SMB sessions
679 */
680 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700682 /* loop through server session structures attached to this and
683 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500684 list_for_each(tmp, &server->smb_ses_list) {
685 ses = list_entry(tmp, struct cifsSesInfo,
686 smb_ses_list);
687 ses->status = CifsExiting;
688 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500690 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700692 /* although we can not zero the server struct pointer yet,
693 since there are active requests which may depnd on them,
694 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500695 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500697 smb_ses_list);
698 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700699 }
700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 spin_lock(&GlobalMid_Lock);
702 list_for_each(tmp, &server->pending_mid_q) {
703 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
704 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000705 cFYI(1, "Clearing Mid 0x%x - waking up ",
706 mid_entry->mid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000708 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
711 }
712 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500713 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700715 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
717
Steve Frenchf1914012005-08-18 09:37:34 -0700718 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000719 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700721 /* due to delays on oplock break requests, we need
722 to wait at least 45 seconds before giving up
723 on a request getting a response and going ahead
724 and killing cifsd */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000725 cFYI(1, "Wait for exit from demultiplex thread");
Steve French31ca3bc2005-04-28 22:41:11 -0700726 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 /* if threads still have not exited they are probably never
728 coming home not much else we can do but free the memory */
729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
Steve French31ca3bc2005-04-28 22:41:11 -0700731 /* last chance to mark ses pointers invalid
732 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000733 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700734 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500735 /* BB: This shouldn't be necessary, see above */
736 read_lock(&cifs_tcp_ses_lock);
737 list_for_each(tmp, &server->smb_ses_list) {
738 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
739 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700740 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500741 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700742
Jeff Laytonc359cf32007-11-16 22:22:06 +0000743 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400744 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700745 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400746
747 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000748 if (length > 0)
749 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
750 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000751
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400752 /* if server->tsk was NULL then wait for a signal before exiting */
753 if (!task_to_wake) {
754 set_current_state(TASK_INTERRUPTIBLE);
755 while (!signal_pending(current)) {
756 schedule();
757 set_current_state(TASK_INTERRUPTIBLE);
758 }
759 set_current_state(TASK_RUNNING);
760 }
761
Jeff Layton0468a2c2008-12-01 07:09:35 -0500762 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
Jeff Laytonc359cf32007-11-16 22:22:06 +0000765/* extract the host portion of the UNC string */
766static char *
767extract_hostname(const char *unc)
768{
769 const char *src;
770 char *dst, *delim;
771 unsigned int len;
772
773 /* skip double chars at beginning of string */
774 /* BB: check validity of these bytes? */
775 src = unc + 2;
776
777 /* delimiter between hostname and sharename is always '\\' now */
778 delim = strchr(src, '\\');
779 if (!delim)
780 return ERR_PTR(-EINVAL);
781
782 len = delim - src;
783 dst = kmalloc((len + 1), GFP_KERNEL);
784 if (dst == NULL)
785 return ERR_PTR(-ENOMEM);
786
787 memcpy(dst, src, len);
788 dst[len] = '\0';
789
790 return dst;
791}
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793static int
Steve French50c2f752007-07-13 00:33:32 +0000794cifs_parse_mount_options(char *options, const char *devname,
795 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 char *value;
798 char *data;
799 unsigned int temp_len, i, j;
800 char separator[2];
Jeff Layton9b9d6b242009-07-31 06:56:09 -0400801 short int override_uid = -1;
802 short int override_gid = -1;
803 bool uid_specified = false;
804 bool gid_specified = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000807 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Linus Torvalds12e36b22006-10-13 08:09:29 -0700809 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000810 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000811 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000813 int n = strnlen(nodename, 15);
814 memset(vol->source_rfc1001_name, 0x20, 15);
815 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000816 /* does not have to be perfect mapping since field is
817 informational, only used for servers that do not support
818 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700819 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700823 /* null target name indicates to use *SMBSERVR default called name
824 if we end up sending RFC1001 session initialize */
825 vol->target_rfc1001_name[0] = 0;
Jeff Layton3e4b3e12010-07-19 18:00:17 -0400826 vol->cred_uid = current_uid();
827 vol->linux_uid = current_uid();
David Howellsa001e5b2008-11-14 10:38:47 +1100828 vol->linux_gid = current_gid();
Jeff Laytonf55ed1a2009-05-26 16:28:11 -0400829
830 /* default to only allowing write access to owner of the mount */
831 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Jeremy Allisonac670552005-06-22 17:26:35 -0700834 /* default is always to request posix paths. */
835 vol->posix_paths = 1;
Jeff Laytona0c92172009-05-27 15:40:47 -0400836 /* default to using server inode numbers where available */
837 vol->server_ino = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -0700838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (!options)
840 return 1;
841
Steve French50c2f752007-07-13 00:33:32 +0000842 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000843 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 separator[0] = options[4];
845 options += 5;
846 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000847 cFYI(1, "Null separator not allowed");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 }
Steve French50c2f752007-07-13 00:33:32 +0000850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 while ((data = strsep(&options, separator)) != NULL) {
852 if (!*data)
853 continue;
854 if ((value = strchr(data, '=')) != NULL)
855 *value++ = '\0';
856
Steve French50c2f752007-07-13 00:33:32 +0000857 /* Have to parse this before we parse for "user" */
858 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000860 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 vol->no_xattr = 1;
862 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000863 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 printk(KERN_WARNING
865 "CIFS: invalid or missing username\n");
866 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000867 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000868 /* null user, ie anonymous, authentication */
869 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
871 if (strnlen(value, 200) < 200) {
872 vol->username = value;
873 } else {
874 printk(KERN_WARNING "CIFS: username too long\n");
875 return 1;
876 }
877 } else if (strnicmp(data, "pass", 4) == 0) {
878 if (!value) {
879 vol->password = NULL;
880 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000881 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 /* check if string begins with double comma
883 since that would mean the password really
884 does start with a comma, and would not
885 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000886 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 vol->password = NULL;
888 continue;
889 }
890 }
891 temp_len = strlen(value);
892 /* removed password length check, NTLM passwords
893 can be arbitrarily long */
894
Steve French50c2f752007-07-13 00:33:32 +0000895 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 prematurely null terminated. Commas in password are
897 specified across the cifs mount interface by a double
898 comma ie ,, and a comma used as in other cases ie ','
899 as a parameter delimiter/separator is single and due
900 to the strsep above is temporarily zeroed. */
901
902 /* NB: password legally can have multiple commas and
903 the only illegal character in a password is null */
904
Steve French50c2f752007-07-13 00:33:32 +0000905 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700906 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* reinsert comma */
908 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000909 temp_len += 2; /* move after second comma */
910 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000912 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700913 separator[0]) {
914 /* skip second comma */
915 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000916 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 /* single comma indicating start
918 of next parm */
919 break;
920 }
921 }
922 temp_len++;
923 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000924 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 options = NULL;
926 } else {
927 value[temp_len] = 0;
928 /* point option to start of next parm */
929 options = value + temp_len + 1;
930 }
Steve French50c2f752007-07-13 00:33:32 +0000931 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 double commas to singles. Note that this ends up
933 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700934 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000935 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000936 printk(KERN_WARNING "CIFS: no memory "
937 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700938 return 1;
939 }
Steve French50c2f752007-07-13 00:33:32 +0000940 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000942 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700943 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 /* skip second comma */
945 i++;
946 }
947 }
948 vol->password[j] = 0;
949 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700950 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000951 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000952 printk(KERN_WARNING "CIFS: no memory "
953 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700954 return 1;
955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 strcpy(vol->password, value);
957 }
Jeff Layton58f7f682009-06-10 09:57:55 -0400958 } else if (!strnicmp(data, "ip", 2) ||
959 !strnicmp(data, "addr", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 if (!value || !*value) {
961 vol->UNCip = NULL;
Jeff Layton50b64e32009-06-02 06:55:20 -0400962 } else if (strnlen(value, INET6_ADDRSTRLEN) <
963 INET6_ADDRSTRLEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 vol->UNCip = value;
965 } else {
Steve French50c2f752007-07-13 00:33:32 +0000966 printk(KERN_WARNING "CIFS: ip address "
967 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return 1;
969 }
Steve French50c2f752007-07-13 00:33:32 +0000970 } else if (strnicmp(data, "sec", 3) == 0) {
971 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000972 cERROR(1, "no security value specified");
Steve French50c2f752007-07-13 00:33:32 +0000973 continue;
974 } else if (strnicmp(value, "krb5i", 5) == 0) {
975 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000976 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800977 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000978 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
979 CIFSSEC_MAY_KRB5; */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000980 cERROR(1, "Krb5 cifs privacy not supported");
Steve Frenchbf820672005-12-01 22:32:42 -0800981 return 1;
982 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000983 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchac683922009-05-06 04:16:04 +0000984#ifdef CONFIG_CIFS_EXPERIMENTAL
985 } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
986 vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
987 CIFSSEC_MUST_SIGN;
988 } else if (strnicmp(value, "ntlmssp", 7) == 0) {
989 vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
990#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000992 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000993 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800994 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000995 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800996 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000997 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000998 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800999 } else if (strnicmp(value, "ntlm", 4) == 0) {
1000 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +00001001 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -08001002 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001003 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +00001004 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +00001005#ifdef CONFIG_CIFS_WEAK_PW_HASH
1006 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001007 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001008#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001009 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001010 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001011 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001012 cERROR(1, "bad security option: %s", value);
Steve French50c2f752007-07-13 00:33:32 +00001013 return 1;
1014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 } else if ((strnicmp(data, "unc", 3) == 0)
1016 || (strnicmp(data, "target", 6) == 0)
1017 || (strnicmp(data, "path", 4) == 0)) {
1018 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001019 printk(KERN_WARNING "CIFS: invalid path to "
1020 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return 1; /* needs_arg; */
1022 }
1023 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001024 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001025 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001027 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (strncmp(vol->UNC, "//", 2) == 0) {
1029 vol->UNC[0] = '\\';
1030 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001031 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001033 "CIFS: UNC Path does not begin "
1034 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return 1;
1036 }
1037 } else {
1038 printk(KERN_WARNING "CIFS: UNC name too long\n");
1039 return 1;
1040 }
1041 } else if ((strnicmp(data, "domain", 3) == 0)
1042 || (strnicmp(data, "workgroup", 5) == 0)) {
1043 if (!value || !*value) {
1044 printk(KERN_WARNING "CIFS: invalid domain name\n");
1045 return 1; /* needs_arg; */
1046 }
1047 /* BB are there cases in which a comma can be valid in
1048 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001049 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 vol->domainname = value;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001051 cFYI(1, "Domain name set");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 } else {
Steve French50c2f752007-07-13 00:33:32 +00001053 printk(KERN_WARNING "CIFS: domain name too "
1054 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return 1;
1056 }
Ben Greear3eb9a882010-09-01 17:06:02 -07001057 } else if (strnicmp(data, "srcaddr", 7) == 0) {
1058 vol->srcaddr.ss_family = AF_UNSPEC;
1059
1060 if (!value || !*value) {
1061 printk(KERN_WARNING "CIFS: srcaddr value"
1062 " not specified.\n");
1063 return 1; /* needs_arg; */
1064 }
1065 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
1066 value, strlen(value));
1067 if (i < 0) {
1068 printk(KERN_WARNING "CIFS: Could not parse"
1069 " srcaddr: %s\n",
1070 value);
1071 return 1;
1072 }
Steve French50c2f752007-07-13 00:33:32 +00001073 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1074 if (!value || !*value) {
1075 printk(KERN_WARNING
1076 "CIFS: invalid path prefix\n");
1077 return 1; /* needs_argument */
1078 }
1079 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001080 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001081 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001082 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1083 if (vol->prepath == NULL)
1084 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001085 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001086 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001087 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001088 } else
Steve French50c2f752007-07-13 00:33:32 +00001089 strcpy(vol->prepath, value);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001090 cFYI(1, "prefix path %s", vol->prepath);
Steve French50c2f752007-07-13 00:33:32 +00001091 } else {
1092 printk(KERN_WARNING "CIFS: prefix too long\n");
1093 return 1;
1094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 } else if (strnicmp(data, "iocharset", 9) == 0) {
1096 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001097 printk(KERN_WARNING "CIFS: invalid iocharset "
1098 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return 1; /* needs_arg; */
1100 }
1101 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001102 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001104 /* if iocharset not set then load_nls_default
1105 is used by caller */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001106 cFYI(1, "iocharset set to %s", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 } else {
Steve French63135e02007-07-17 17:34:02 +00001108 printk(KERN_WARNING "CIFS: iocharset name "
1109 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return 1;
1111 }
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001112 } else if (!strnicmp(data, "uid", 3) && value && *value) {
1113 vol->linux_uid = simple_strtoul(value, &value, 0);
1114 uid_specified = true;
1115 } else if (!strnicmp(data, "forceuid", 8)) {
1116 override_uid = 1;
1117 } else if (!strnicmp(data, "noforceuid", 10)) {
1118 override_uid = 0;
1119 } else if (!strnicmp(data, "gid", 3) && value && *value) {
1120 vol->linux_gid = simple_strtoul(value, &value, 0);
1121 gid_specified = true;
1122 } else if (!strnicmp(data, "forcegid", 8)) {
1123 override_gid = 1;
1124 } else if (!strnicmp(data, "noforcegid", 10)) {
1125 override_gid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 } else if (strnicmp(data, "file_mode", 4) == 0) {
1127 if (value && *value) {
1128 vol->file_mode =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1132 if (value && *value) {
1133 vol->dir_mode =
1134 simple_strtoul(value, &value, 0);
1135 }
1136 } else if (strnicmp(data, "dirmode", 4) == 0) {
1137 if (value && *value) {
1138 vol->dir_mode =
1139 simple_strtoul(value, &value, 0);
1140 }
1141 } else if (strnicmp(data, "port", 4) == 0) {
1142 if (value && *value) {
1143 vol->port =
1144 simple_strtoul(value, &value, 0);
1145 }
1146 } else if (strnicmp(data, "rsize", 5) == 0) {
1147 if (value && *value) {
1148 vol->rsize =
1149 simple_strtoul(value, &value, 0);
1150 }
1151 } else if (strnicmp(data, "wsize", 5) == 0) {
1152 if (value && *value) {
1153 vol->wsize =
1154 simple_strtoul(value, &value, 0);
1155 }
1156 } else if (strnicmp(data, "sockopt", 5) == 0) {
Steve French6a5fa2362010-01-01 01:28:43 +00001157 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001158 cERROR(1, "no socket option specified");
Steve French6a5fa2362010-01-01 01:28:43 +00001159 continue;
1160 } else if (strnicmp(value, "TCP_NODELAY", 11) == 0) {
1161 vol->sockopt_tcp_nodelay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1164 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001165 cFYI(1, "invalid (empty) netbiosname");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 } else {
Steve French50c2f752007-07-13 00:33:32 +00001167 memset(vol->source_rfc1001_name, 0x20, 15);
1168 for (i = 0; i < 15; i++) {
1169 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 valid in this workstation netbios name (and need
1171 special handling)? */
1172
1173 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001174 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 break;
Steve French50c2f752007-07-13 00:33:32 +00001176 else
1177 vol->source_rfc1001_name[i] =
1178 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 }
1180 /* The string has 16th byte zero still from
1181 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001182 if ((i == 15) && (value[i] != 0))
1183 printk(KERN_WARNING "CIFS: netbiosname"
1184 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001185 }
1186 } else if (strnicmp(data, "servern", 7) == 0) {
1187 /* servernetbiosname specified override *SMBSERVER */
1188 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001189 cFYI(1, "empty server netbiosname specified");
Steve Frencha10faeb22005-08-22 21:38:31 -07001190 } else {
1191 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001192 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001193
Steve French50c2f752007-07-13 00:33:32 +00001194 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001195 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001196 valid in this workstation netbios name
1197 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001198
Steve French50c2f752007-07-13 00:33:32 +00001199 /* user or mount helper must uppercase
1200 the netbiosname */
1201 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001202 break;
1203 else
Steve French50c2f752007-07-13 00:33:32 +00001204 vol->target_rfc1001_name[i] =
1205 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001206 }
1207 /* The string has 16th byte zero still from
1208 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001209 if ((i == 15) && (value[i] != 0))
1210 printk(KERN_WARNING "CIFS: server net"
1211 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
1213 } else if (strnicmp(data, "credentials", 4) == 0) {
1214 /* ignore */
1215 } else if (strnicmp(data, "version", 3) == 0) {
1216 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001217 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 /* ignore */
Steve French71a394f2009-06-26 04:07:18 +00001219 } else if (strnicmp(data, "rw", 2) == 0) {
1220 /* ignore */
1221 } else if (strnicmp(data, "ro", 2) == 0) {
1222 /* ignore */
Steve Frenchedf1ae42008-10-29 00:47:57 +00001223 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1224 vol->noblocksnd = 1;
1225 } else if (strnicmp(data, "noautotune", 10) == 0) {
1226 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 } else if ((strnicmp(data, "suid", 4) == 0) ||
1228 (strnicmp(data, "nosuid", 6) == 0) ||
1229 (strnicmp(data, "exec", 4) == 0) ||
1230 (strnicmp(data, "noexec", 6) == 0) ||
1231 (strnicmp(data, "nodev", 5) == 0) ||
1232 (strnicmp(data, "noauto", 6) == 0) ||
1233 (strnicmp(data, "dev", 3) == 0)) {
1234 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001235 uses these opts to set flags, and the flags are read
1236 by the kernel vfs layer before we get here (ie
1237 before read super) so there is no point trying to
1238 parse these options again and set anything and it
1239 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 } else if (strnicmp(data, "hard", 4) == 0) {
1242 vol->retry = 1;
1243 } else if (strnicmp(data, "soft", 4) == 0) {
1244 vol->retry = 0;
1245 } else if (strnicmp(data, "perm", 4) == 0) {
1246 vol->noperm = 0;
1247 } else if (strnicmp(data, "noperm", 6) == 0) {
1248 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001249 } else if (strnicmp(data, "mapchars", 8) == 0) {
1250 vol->remap = 1;
1251 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1252 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001253 } else if (strnicmp(data, "sfu", 3) == 0) {
1254 vol->sfu_emul = 1;
1255 } else if (strnicmp(data, "nosfu", 5) == 0) {
1256 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001257 } else if (strnicmp(data, "nodfs", 5) == 0) {
1258 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001259 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1260 vol->posix_paths = 1;
1261 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1262 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001263 } else if (strnicmp(data, "nounix", 6) == 0) {
1264 vol->no_linux_ext = 1;
1265 } else if (strnicmp(data, "nolinux", 7) == 0) {
1266 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001267 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001268 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001269 vol->nocase = 1;
Jeff Laytonf636a342010-07-26 10:29:58 -04001270 } else if (strnicmp(data, "mand", 4) == 0) {
1271 /* ignore */
1272 } else if (strnicmp(data, "nomand", 6) == 0) {
1273 /* ignore */
1274 } else if (strnicmp(data, "_netdev", 7) == 0) {
1275 /* ignore */
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001276 } else if (strnicmp(data, "brl", 3) == 0) {
1277 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001278 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001279 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001280 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001281 /* turn off mandatory locking in mode
1282 if remote locking is turned off since the
1283 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001284 if (vol->file_mode ==
1285 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001286 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001287 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1288 /* will take the shorter form "forcemand" as well */
1289 /* This mount option will force use of mandatory
1290 (DOS/Windows style) byte range locks, instead of
1291 using posix advisory byte range locks, even if the
1292 Unix extensions are available and posix locks would
1293 be supported otherwise. If Unix extensions are not
1294 negotiated this has no effect since mandatory locks
1295 would be used (mandatory locks is all that those
1296 those servers support) */
1297 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 } else if (strnicmp(data, "setuids", 7) == 0) {
1299 vol->setuids = 1;
1300 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1301 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001302 } else if (strnicmp(data, "dynperm", 7) == 0) {
1303 vol->dynperm = true;
1304 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1305 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 } else if (strnicmp(data, "nohard", 6) == 0) {
1307 vol->retry = 0;
1308 } else if (strnicmp(data, "nosoft", 6) == 0) {
1309 vol->retry = 1;
1310 } else if (strnicmp(data, "nointr", 6) == 0) {
1311 vol->intr = 0;
1312 } else if (strnicmp(data, "intr", 4) == 0) {
1313 vol->intr = 1;
Steve Frenchbe652442009-02-23 15:21:59 +00001314 } else if (strnicmp(data, "nostrictsync", 12) == 0) {
1315 vol->nostrictsync = 1;
1316 } else if (strnicmp(data, "strictsync", 10) == 0) {
1317 vol->nostrictsync = 0;
Steve French50c2f752007-07-13 00:33:32 +00001318 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001320 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001322 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001323 vol->cifs_acl = 1;
1324 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1325 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001326 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001328 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001330#ifdef CONFIG_CIFS_EXPERIMENTAL
1331 } else if (strnicmp(data, "locallease", 6) == 0) {
1332 vol->local_lease = 1;
1333#endif
Steve French50c2f752007-07-13 00:33:32 +00001334 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001335 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001336 } else if (strnicmp(data, "seal", 4) == 0) {
1337 /* we do not do the following in secFlags because seal
1338 is a per tree connection (mount) not a per socket
1339 or per-smb connection option in the protocol */
1340 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1341 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001342 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001344 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 vol->direct_io = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001347 printk(KERN_WARNING "CIFS: Mount option noac not "
1348 "supported. Instead set "
1349 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05301350 } else if (strnicmp(data, "fsc", 3) == 0) {
1351 vol->fsc = true;
Stefan Metzmacher736a3322010-07-30 14:56:00 +02001352 } else if (strnicmp(data, "mfsymlinks", 10) == 0) {
1353 vol->mfsymlinks = true;
Jeff Layton0eb8a132010-10-06 19:51:12 -04001354 } else if (strnicmp(data, "multiuser", 8) == 0) {
1355 vol->multiuser = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 } else
Steve French50c2f752007-07-13 00:33:32 +00001357 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1358 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
1360 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001361 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001362 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1363 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 return 1;
1365 }
1366 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001367 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001368 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001370 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if (strncmp(vol->UNC, "//", 2) == 0) {
1372 vol->UNC[0] = '\\';
1373 vol->UNC[1] = '\\';
1374 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001375 printk(KERN_WARNING "CIFS: UNC Path does not "
1376 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return 1;
1378 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001379 value = strpbrk(vol->UNC+2, "/\\");
1380 if (value)
1381 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 } else {
1383 printk(KERN_WARNING "CIFS: UNC name too long\n");
1384 return 1;
1385 }
1386 }
Jeff Layton0eb8a132010-10-06 19:51:12 -04001387
1388 if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
1389 cERROR(1, "Multiuser mounts currently require krb5 "
1390 "authentication!");
1391 return 1;
1392 }
1393
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001394 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 vol->UNCip = &vol->UNC[2];
1396
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001397 if (uid_specified)
1398 vol->override_uid = override_uid;
1399 else if (override_uid == 1)
1400 printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
1401 "specified with no uid= option.\n");
1402
1403 if (gid_specified)
1404 vol->override_gid = override_gid;
1405 else if (override_gid == 1)
1406 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
1407 "specified with no gid= option.\n");
1408
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return 0;
1410}
1411
Ben Greear3eb9a882010-09-01 17:06:02 -07001412/** Returns true if srcaddr isn't specified and rhs isn't
1413 * specified, or if srcaddr is specified and
1414 * matches the IP address of the rhs argument.
1415 */
Jeff Layton45151482010-07-06 20:43:02 -04001416static bool
Ben Greear3eb9a882010-09-01 17:06:02 -07001417srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
1418{
1419 switch (srcaddr->sa_family) {
1420 case AF_UNSPEC:
1421 return (rhs->sa_family == AF_UNSPEC);
1422 case AF_INET: {
1423 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1424 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1425 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1426 }
1427 case AF_INET6: {
1428 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1429 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
1430 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1431 }
1432 default:
1433 WARN_ON(1);
1434 return false; /* don't expect to be here */
1435 }
1436}
1437
1438
1439static bool
1440match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1441 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
Jeff Layton45151482010-07-06 20:43:02 -04001443 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1444 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1445
1446 switch (addr->sa_family) {
1447 case AF_INET:
1448 if (addr4->sin_addr.s_addr !=
1449 server->addr.sockAddr.sin_addr.s_addr)
1450 return false;
1451 if (addr4->sin_port &&
1452 addr4->sin_port != server->addr.sockAddr.sin_port)
1453 return false;
1454 break;
1455 case AF_INET6:
1456 if (!ipv6_addr_equal(&addr6->sin6_addr,
1457 &server->addr.sockAddr6.sin6_addr))
1458 return false;
1459 if (addr6->sin6_scope_id !=
1460 server->addr.sockAddr6.sin6_scope_id)
1461 return false;
1462 if (addr6->sin6_port &&
1463 addr6->sin6_port != server->addr.sockAddr6.sin6_port)
1464 return false;
1465 break;
1466 }
1467
Ben Greear3eb9a882010-09-01 17:06:02 -07001468 if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
1469 return false;
1470
Jeff Layton45151482010-07-06 20:43:02 -04001471 return true;
1472}
1473
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001474static bool
1475match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
1476{
1477 unsigned int secFlags;
1478
1479 if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
1480 secFlags = vol->secFlg;
1481 else
1482 secFlags = global_secflags | vol->secFlg;
1483
1484 switch (server->secType) {
1485 case LANMAN:
1486 if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
1487 return false;
1488 break;
1489 case NTLMv2:
1490 if (!(secFlags & CIFSSEC_MAY_NTLMV2))
1491 return false;
1492 break;
1493 case NTLM:
1494 if (!(secFlags & CIFSSEC_MAY_NTLM))
1495 return false;
1496 break;
1497 case Kerberos:
1498 if (!(secFlags & CIFSSEC_MAY_KRB5))
1499 return false;
1500 break;
1501 case RawNTLMSSP:
1502 if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
1503 return false;
1504 break;
1505 default:
1506 /* shouldn't happen */
1507 return false;
1508 }
1509
1510 /* now check if signing mode is acceptible */
1511 if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
1512 (server->secMode & SECMODE_SIGN_REQUIRED))
1513 return false;
1514 else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
1515 (server->secMode &
1516 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
1517 return false;
1518
1519 return true;
1520}
1521
Jeff Layton45151482010-07-06 20:43:02 -04001522static struct TCP_Server_Info *
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001523cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
Jeff Layton45151482010-07-06 20:43:02 -04001524{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001525 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Jeff Laytone7ddee92008-11-14 13:44:38 -05001527 write_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001528 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Ben Greear3eb9a882010-09-01 17:06:02 -07001529 if (!match_address(server, addr,
1530 (struct sockaddr *)&vol->srcaddr))
Jeff Layton45151482010-07-06 20:43:02 -04001531 continue;
Steve French50c2f752007-07-13 00:33:32 +00001532
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001533 if (!match_security(server, vol))
1534 continue;
1535
Jeff Laytone7ddee92008-11-14 13:44:38 -05001536 ++server->srv_count;
1537 write_unlock(&cifs_tcp_ses_lock);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001538 cFYI(1, "Existing tcp session with server found");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001539 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001541 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 return NULL;
1543}
1544
Jeff Layton14fbf502008-11-14 13:53:46 -05001545static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001546cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001548 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Jeff Laytone7ddee92008-11-14 13:44:38 -05001550 write_lock(&cifs_tcp_ses_lock);
1551 if (--server->srv_count > 0) {
1552 write_unlock(&cifs_tcp_ses_lock);
1553 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001555
Jeff Laytone7ddee92008-11-14 13:44:38 -05001556 list_del_init(&server->tcp_ses_list);
1557 write_unlock(&cifs_tcp_ses_lock);
1558
1559 spin_lock(&GlobalMid_Lock);
1560 server->tcpStatus = CifsExiting;
1561 spin_unlock(&GlobalMid_Lock);
1562
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301563 cifs_fscache_release_client_cookie(server);
1564
Jeff Laytone7ddee92008-11-14 13:44:38 -05001565 task = xchg(&server->tsk, NULL);
1566 if (task)
1567 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568}
1569
Jeff Layton63c038c2008-12-01 18:41:46 -05001570static struct TCP_Server_Info *
1571cifs_get_tcp_session(struct smb_vol *volume_info)
1572{
1573 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001574 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05001575 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1576 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1577 int rc;
1578
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001579 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05001580
Joe Perchesb6b38f72010-04-21 03:50:45 +00001581 cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001582
Jeff Layton63c038c2008-12-01 18:41:46 -05001583 if (volume_info->UNCip && volume_info->UNC) {
Jeff Layton50d97162010-07-06 20:43:01 -04001584 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
1585 volume_info->UNCip,
David Howells67b76262010-07-22 18:33:01 +01001586 strlen(volume_info->UNCip),
Jeff Layton50d97162010-07-06 20:43:01 -04001587 volume_info->port);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001588 if (!rc) {
Jeff Layton63c038c2008-12-01 18:41:46 -05001589 /* we failed translating address */
1590 rc = -EINVAL;
1591 goto out_err;
1592 }
Jeff Layton63c038c2008-12-01 18:41:46 -05001593 } else if (volume_info->UNCip) {
1594 /* BB using ip addr as tcp_ses name to connect to the
1595 DFS root below */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001596 cERROR(1, "Connecting to DFS root not implemented yet");
Jeff Layton63c038c2008-12-01 18:41:46 -05001597 rc = -EINVAL;
1598 goto out_err;
1599 } else /* which tcp_sess DFS root would we conect to */ {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001600 cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
1601 "unc=//192.168.1.100/public) specified");
Jeff Layton63c038c2008-12-01 18:41:46 -05001602 rc = -EINVAL;
1603 goto out_err;
1604 }
1605
1606 /* see if we already have a matching tcp_ses */
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001607 tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05001608 if (tcp_ses)
1609 return tcp_ses;
1610
1611 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1612 if (!tcp_ses) {
1613 rc = -ENOMEM;
1614 goto out_err;
1615 }
1616
1617 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1618 if (IS_ERR(tcp_ses->hostname)) {
1619 rc = PTR_ERR(tcp_ses->hostname);
1620 goto out_err;
1621 }
1622
1623 tcp_ses->noblocksnd = volume_info->noblocksnd;
1624 tcp_ses->noautotune = volume_info->noautotune;
Steve French6a5fa2362010-01-01 01:28:43 +00001625 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
Jeff Layton63c038c2008-12-01 18:41:46 -05001626 atomic_set(&tcp_ses->inFlight, 0);
1627 init_waitqueue_head(&tcp_ses->response_q);
1628 init_waitqueue_head(&tcp_ses->request_q);
1629 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1630 mutex_init(&tcp_ses->srv_mutex);
1631 memcpy(tcp_ses->workstation_RFC1001_name,
1632 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1633 memcpy(tcp_ses->server_RFC1001_name,
1634 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05001635 tcp_ses->session_estab = false;
Jeff Layton63c038c2008-12-01 18:41:46 -05001636 tcp_ses->sequence_number = 0;
1637 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1638 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1639
1640 /*
1641 * at this point we are the only ones with the pointer
1642 * to the struct since the kernel thread not created yet
1643 * no need to spinlock this init of tcpStatus or srv_count
1644 */
1645 tcp_ses->tcpStatus = CifsNew;
Ben Greear3eb9a882010-09-01 17:06:02 -07001646 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
1647 sizeof(tcp_ses->srcaddr));
Jeff Layton63c038c2008-12-01 18:41:46 -05001648 ++tcp_ses->srv_count;
1649
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001650 if (addr.ss_family == AF_INET6) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001651 cFYI(1, "attempting ipv6 connect");
Jeff Layton63c038c2008-12-01 18:41:46 -05001652 /* BB should we allow ipv6 on port 139? */
1653 /* other OS never observed in Wild doing 139 with v6 */
1654 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1655 sizeof(struct sockaddr_in6));
Jeff Laytond5c56052008-12-01 18:42:33 -05001656 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001657 } else {
1658 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1659 sizeof(struct sockaddr_in));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001660 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001661 }
1662 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001663 cERROR(1, "Error connecting to socket. Aborting operation");
Jeff Layton63c038c2008-12-01 18:41:46 -05001664 goto out_err;
1665 }
1666
1667 /*
1668 * since we're in a cifs function already, we know that
1669 * this will succeed. No need for try_module_get().
1670 */
1671 __module_get(THIS_MODULE);
1672 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1673 tcp_ses, "cifsd");
1674 if (IS_ERR(tcp_ses->tsk)) {
1675 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001676 cERROR(1, "error %d create cifsd thread", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05001677 module_put(THIS_MODULE);
1678 goto out_err;
1679 }
1680
1681 /* thread spawned, put it on the list */
1682 write_lock(&cifs_tcp_ses_lock);
1683 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1684 write_unlock(&cifs_tcp_ses_lock);
1685
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301686 cifs_fscache_get_client_cookie(tcp_ses);
1687
Jeff Layton63c038c2008-12-01 18:41:46 -05001688 return tcp_ses;
1689
1690out_err:
1691 if (tcp_ses) {
Steve French8347a5c2009-10-06 18:31:29 +00001692 if (!IS_ERR(tcp_ses->hostname))
1693 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05001694 if (tcp_ses->ssocket)
1695 sock_release(tcp_ses->ssocket);
1696 kfree(tcp_ses);
1697 }
1698 return ERR_PTR(rc);
1699}
1700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701static struct cifsSesInfo *
Jeff Layton4ff67b72010-07-06 20:43:02 -04001702cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 struct cifsSesInfo *ses;
1705
Jeff Layton14fbf502008-11-14 13:53:46 -05001706 write_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04001707 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1708 switch (server->secType) {
1709 case Kerberos:
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001710 if (vol->cred_uid != ses->cred_uid)
Jeff Layton4ff67b72010-07-06 20:43:02 -04001711 continue;
1712 break;
1713 default:
1714 /* anything else takes username/password */
1715 if (strncmp(ses->userName, vol->username,
1716 MAX_USERNAME_SIZE))
1717 continue;
1718 if (strlen(vol->username) != 0 &&
Jeff Layton24e6cf92010-08-23 11:38:04 -04001719 ses->password != NULL &&
Jeff Laytonfc87a402010-08-18 13:13:39 -04001720 strncmp(ses->password,
1721 vol->password ? vol->password : "",
Jeff Layton4ff67b72010-07-06 20:43:02 -04001722 MAX_PASSWORD_SIZE))
1723 continue;
1724 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001725 ++ses->ses_count;
1726 write_unlock(&cifs_tcp_ses_lock);
1727 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001729 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return NULL;
1731}
1732
Jeff Layton14fbf502008-11-14 13:53:46 -05001733static void
1734cifs_put_smb_ses(struct cifsSesInfo *ses)
1735{
1736 int xid;
1737 struct TCP_Server_Info *server = ses->server;
1738
Jeff Layton36988c72010-04-24 07:57:43 -04001739 cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count);
Jeff Layton14fbf502008-11-14 13:53:46 -05001740 write_lock(&cifs_tcp_ses_lock);
1741 if (--ses->ses_count > 0) {
1742 write_unlock(&cifs_tcp_ses_lock);
1743 return;
1744 }
1745
1746 list_del_init(&ses->smb_ses_list);
1747 write_unlock(&cifs_tcp_ses_lock);
1748
1749 if (ses->status == CifsGood) {
1750 xid = GetXid();
1751 CIFSSMBLogoff(xid, ses);
1752 _FreeXid(xid);
1753 }
1754 sesInfoFree(ses);
1755 cifs_put_tcp_session(server);
1756}
1757
Jeff Layton36988c72010-04-24 07:57:43 -04001758static struct cifsSesInfo *
1759cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1760{
1761 int rc = -ENOMEM, xid;
1762 struct cifsSesInfo *ses;
1763
1764 xid = GetXid();
1765
Jeff Layton4ff67b72010-07-06 20:43:02 -04001766 ses = cifs_find_smb_ses(server, volume_info);
Jeff Layton36988c72010-04-24 07:57:43 -04001767 if (ses) {
1768 cFYI(1, "Existing smb sess found (status=%d)", ses->status);
1769
Jeff Layton36988c72010-04-24 07:57:43 -04001770 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001771 rc = cifs_negotiate_protocol(xid, ses);
1772 if (rc) {
1773 mutex_unlock(&ses->session_mutex);
1774 /* problem -- put our ses reference */
1775 cifs_put_smb_ses(ses);
1776 FreeXid(xid);
1777 return ERR_PTR(rc);
1778 }
Jeff Layton36988c72010-04-24 07:57:43 -04001779 if (ses->need_reconnect) {
1780 cFYI(1, "Session needs reconnect");
1781 rc = cifs_setup_session(xid, ses,
1782 volume_info->local_nls);
1783 if (rc) {
1784 mutex_unlock(&ses->session_mutex);
1785 /* problem -- put our reference */
1786 cifs_put_smb_ses(ses);
1787 FreeXid(xid);
1788 return ERR_PTR(rc);
1789 }
1790 }
1791 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04001792
1793 /* existing SMB ses has a server reference already */
1794 cifs_put_tcp_session(server);
Jeff Layton36988c72010-04-24 07:57:43 -04001795 FreeXid(xid);
1796 return ses;
1797 }
1798
1799 cFYI(1, "Existing smb sess not found");
1800 ses = sesInfoAlloc();
1801 if (ses == NULL)
1802 goto get_ses_fail;
1803
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -05001804 ses->tilen = 0;
1805 ses->tiblob = NULL;
Jeff Layton36988c72010-04-24 07:57:43 -04001806 /* new SMB session uses our server ref */
1807 ses->server = server;
1808 if (server->addr.sockAddr6.sin6_family == AF_INET6)
1809 sprintf(ses->serverName, "%pI6",
1810 &server->addr.sockAddr6.sin6_addr);
1811 else
1812 sprintf(ses->serverName, "%pI4",
1813 &server->addr.sockAddr.sin_addr.s_addr);
1814
1815 if (volume_info->username)
1816 strncpy(ses->userName, volume_info->username,
1817 MAX_USERNAME_SIZE);
1818
1819 /* volume_info->password freed at unmount */
1820 if (volume_info->password) {
1821 ses->password = kstrdup(volume_info->password, GFP_KERNEL);
1822 if (!ses->password)
1823 goto get_ses_fail;
1824 }
1825 if (volume_info->domainname) {
1826 int len = strlen(volume_info->domainname);
1827 ses->domainName = kmalloc(len + 1, GFP_KERNEL);
1828 if (ses->domainName)
1829 strcpy(ses->domainName, volume_info->domainname);
1830 }
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001831 ses->cred_uid = volume_info->cred_uid;
Jeff Layton36988c72010-04-24 07:57:43 -04001832 ses->linux_uid = volume_info->linux_uid;
1833 ses->overrideSecFlg = volume_info->secFlg;
1834
1835 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001836 rc = cifs_negotiate_protocol(xid, ses);
1837 if (!rc)
1838 rc = cifs_setup_session(xid, ses, volume_info->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04001839 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00001840 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04001841 goto get_ses_fail;
1842
1843 /* success, put it on the list */
1844 write_lock(&cifs_tcp_ses_lock);
1845 list_add(&ses->smb_ses_list, &server->smb_ses_list);
1846 write_unlock(&cifs_tcp_ses_lock);
1847
1848 FreeXid(xid);
1849 return ses;
1850
1851get_ses_fail:
1852 sesInfoFree(ses);
1853 FreeXid(xid);
1854 return ERR_PTR(rc);
1855}
1856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001858cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
1860 struct list_head *tmp;
1861 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
Jeff Laytonf1987b42008-11-15 11:12:47 -05001863 write_lock(&cifs_tcp_ses_lock);
1864 list_for_each(tmp, &ses->tcon_list) {
1865 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1866 if (tcon->tidStatus == CifsExiting)
1867 continue;
1868 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 continue;
1870
Jeff Laytonf1987b42008-11-15 11:12:47 -05001871 ++tcon->tc_count;
1872 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 return tcon;
1874 }
Jeff Laytonf1987b42008-11-15 11:12:47 -05001875 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 return NULL;
1877}
1878
Jeff Laytonf1987b42008-11-15 11:12:47 -05001879static void
1880cifs_put_tcon(struct cifsTconInfo *tcon)
1881{
1882 int xid;
1883 struct cifsSesInfo *ses = tcon->ses;
1884
Jeff Laytond00c28d2010-04-24 07:57:44 -04001885 cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001886 write_lock(&cifs_tcp_ses_lock);
1887 if (--tcon->tc_count > 0) {
1888 write_unlock(&cifs_tcp_ses_lock);
1889 return;
1890 }
1891
1892 list_del_init(&tcon->tcon_list);
1893 write_unlock(&cifs_tcp_ses_lock);
1894
1895 xid = GetXid();
1896 CIFSSMBTDis(xid, tcon);
1897 _FreeXid(xid);
1898
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301899 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00001900 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001901 cifs_put_smb_ses(ses);
1902}
1903
Jeff Laytond00c28d2010-04-24 07:57:44 -04001904static struct cifsTconInfo *
1905cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
1906{
1907 int rc, xid;
1908 struct cifsTconInfo *tcon;
1909
1910 tcon = cifs_find_tcon(ses, volume_info->UNC);
1911 if (tcon) {
1912 cFYI(1, "Found match on UNC path");
1913 /* existing tcon already has a reference */
1914 cifs_put_smb_ses(ses);
1915 if (tcon->seal != volume_info->seal)
1916 cERROR(1, "transport encryption setting "
1917 "conflicts with existing tid");
1918 return tcon;
1919 }
1920
1921 tcon = tconInfoAlloc();
1922 if (tcon == NULL) {
1923 rc = -ENOMEM;
1924 goto out_fail;
1925 }
1926
1927 tcon->ses = ses;
1928 if (volume_info->password) {
1929 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
1930 if (!tcon->password) {
1931 rc = -ENOMEM;
1932 goto out_fail;
1933 }
1934 }
1935
1936 if (strchr(volume_info->UNC + 3, '\\') == NULL
1937 && strchr(volume_info->UNC + 3, '/') == NULL) {
1938 cERROR(1, "Missing share name");
1939 rc = -ENODEV;
1940 goto out_fail;
1941 }
1942
1943 /* BB Do we need to wrap session_mutex around
1944 * this TCon call and Unix SetFS as
1945 * we do on SessSetup and reconnect? */
1946 xid = GetXid();
1947 rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls);
1948 FreeXid(xid);
1949 cFYI(1, "CIFS Tcon rc = %d", rc);
1950 if (rc)
1951 goto out_fail;
1952
1953 if (volume_info->nodfs) {
1954 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
1955 cFYI(1, "DFS disabled (%d)", tcon->Flags);
1956 }
1957 tcon->seal = volume_info->seal;
1958 /* we can have only one retry value for a connection
1959 to a share so for resources mounted more than once
1960 to the same server share the last value passed in
1961 for the retry flag is used */
1962 tcon->retry = volume_info->retry;
1963 tcon->nocase = volume_info->nocase;
1964 tcon->local_lease = volume_info->local_lease;
1965
1966 write_lock(&cifs_tcp_ses_lock);
1967 list_add(&tcon->tcon_list, &ses->tcon_list);
1968 write_unlock(&cifs_tcp_ses_lock);
1969
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301970 cifs_fscache_get_super_cookie(tcon);
1971
Jeff Laytond00c28d2010-04-24 07:57:44 -04001972 return tcon;
1973
1974out_fail:
1975 tconInfoFree(tcon);
1976 return ERR_PTR(rc);
1977}
1978
Jeff Layton9d002df2010-10-06 19:51:11 -04001979void
1980cifs_put_tlink(struct tcon_link *tlink)
1981{
1982 if (!tlink || IS_ERR(tlink))
1983 return;
1984
1985 if (!atomic_dec_and_test(&tlink->tl_count) ||
1986 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
1987 tlink->tl_time = jiffies;
1988 return;
1989 }
1990
1991 if (!IS_ERR(tlink_tcon(tlink)))
1992 cifs_put_tcon(tlink_tcon(tlink));
1993 kfree(tlink);
1994 return;
1995}
Jeff Laytond00c28d2010-04-24 07:57:44 -04001996
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997int
Steve French50c2f752007-07-13 00:33:32 +00001998get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1999 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00002000 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 char *temp_unc;
2003 int rc = 0;
2004
2005 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00002006 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
2008 if (pSesInfo->ipc_tid == 0) {
2009 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00002010 strnlen(pSesInfo->serverName,
2011 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 + 1 + 4 /* slash IPC$ */ + 2,
2013 GFP_KERNEL);
2014 if (temp_unc == NULL)
2015 return -ENOMEM;
2016 temp_unc[0] = '\\';
2017 temp_unc[1] = '\\';
2018 strcpy(temp_unc + 2, pSesInfo->serverName);
2019 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
2020 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002021 cFYI(1, "CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 kfree(temp_unc);
2023 }
2024 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00002025 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07002026 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00002027 /* BB map targetUNCs to dfs_info3 structures, here or
2028 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 return rc;
2031}
2032
Jeff Layton09e50d52008-07-23 10:11:19 -04002033#ifdef CONFIG_DEBUG_LOCK_ALLOC
2034static struct lock_class_key cifs_key[2];
2035static struct lock_class_key cifs_slock_key[2];
2036
2037static inline void
2038cifs_reclassify_socket4(struct socket *sock)
2039{
2040 struct sock *sk = sock->sk;
2041 BUG_ON(sock_owned_by_user(sk));
2042 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2043 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2044}
2045
2046static inline void
2047cifs_reclassify_socket6(struct socket *sock)
2048{
2049 struct sock *sk = sock->sk;
2050 BUG_ON(sock_owned_by_user(sk));
2051 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2052 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2053}
2054#else
2055static inline void
2056cifs_reclassify_socket4(struct socket *sock)
2057{
2058}
2059
2060static inline void
2061cifs_reclassify_socket6(struct socket *sock)
2062{
2063}
2064#endif
2065
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002067static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068{
Steve French50c2f752007-07-13 00:33:32 +00002069 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Steve French50c2f752007-07-13 00:33:32 +00002071 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 /* mask a nibble at a time and encode */
2073 target[j] = 'A' + (0x0F & (source[i] >> 4));
2074 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002075 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 }
2077
2078}
2079
Ben Greear3eb9a882010-09-01 17:06:02 -07002080static int
2081bind_socket(struct TCP_Server_Info *server)
2082{
2083 int rc = 0;
2084 if (server->srcaddr.ss_family != AF_UNSPEC) {
2085 /* Bind to the specified local IP address */
2086 struct socket *socket = server->ssocket;
2087 rc = socket->ops->bind(socket,
2088 (struct sockaddr *) &server->srcaddr,
2089 sizeof(server->srcaddr));
2090 if (rc < 0) {
2091 struct sockaddr_in *saddr4;
2092 struct sockaddr_in6 *saddr6;
2093 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2094 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2095 if (saddr6->sin6_family == AF_INET6)
2096 cERROR(1, "cifs: "
2097 "Failed to bind to: %pI6c, error: %d\n",
2098 &saddr6->sin6_addr, rc);
2099 else
2100 cERROR(1, "cifs: "
2101 "Failed to bind to: %pI4, error: %d\n",
2102 &saddr4->sin_addr.s_addr, rc);
2103 }
2104 }
2105 return rc;
2106}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002109ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110{
2111 int rc = 0;
Steve French6a5fa2362010-01-01 01:28:43 +00002112 int val;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002113 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002115 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002117 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002118 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002119 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002121 cERROR(1, "Error %d creating socket", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002124
2125 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002126 cFYI(1, "Socket created");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002127 server->ssocket = socket;
2128 socket->sk->sk_allocation = GFP_NOFS;
2129 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 }
2131
Ben Greear3eb9a882010-09-01 17:06:02 -07002132 rc = bind_socket(server);
2133 if (rc < 0)
2134 return rc;
2135
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002136 /* user overrode default port */
2137 if (server->addr.sockAddr.sin_port) {
2138 rc = socket->ops->connect(socket, (struct sockaddr *)
2139 &server->addr.sockAddr,
2140 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002142 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00002143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002145 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00002146 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002148 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
2150 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002151 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
2152 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
2153 rc = socket->ops->connect(socket,
2154 (struct sockaddr *)
2155 &server->addr.sockAddr,
2156 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002158 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160 }
2161 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002162 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
2163 rc = socket->ops->connect(socket, (struct sockaddr *)
2164 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002165 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00002166 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002167 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 }
2169
2170 /* give up here - unless we want to retry on different
2171 protocol families some day */
2172 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002173 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002174 server->addr.sockAddr.sin_port = orig_port;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002175 cFYI(1, "Error %d connecting to server via ipv4", rc);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002176 sock_release(socket);
2177 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 return rc;
2179 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002180
2181
2182 /*
2183 * Eventually check for other socket options to change from
2184 * the default. sock_setsockopt not used because it expects
2185 * user space buffer
2186 */
2187 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002188 socket->sk->sk_sndtimeo = 5 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00002189
Steve Frenchb387eae2005-10-10 14:21:15 -07002190 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002191 if (server->noautotune) {
2192 if (socket->sk->sk_sndbuf < (200 * 1024))
2193 socket->sk->sk_sndbuf = 200 * 1024;
2194 if (socket->sk->sk_rcvbuf < (140 * 1024))
2195 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00002196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Steve French6a5fa2362010-01-01 01:28:43 +00002198 if (server->tcp_nodelay) {
2199 val = 1;
2200 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
2201 (char *)&val, sizeof(val));
2202 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002203 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00002204 }
2205
Joe Perchesb6b38f72010-04-21 03:50:45 +00002206 cFYI(1, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002207 socket->sk->sk_sndbuf,
Joe Perchesb6b38f72010-04-21 03:50:45 +00002208 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002211 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00002213 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00002215 struct rfc1002_session_packet *ses_init_buf;
2216 struct smb_hdr *smb_buf;
2217 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2218 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002219 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002221 if (server->server_RFC1001_name &&
2222 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002223 rfc1002mangle(ses_init_buf->trailer.
2224 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002225 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05002226 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002227 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05002228 rfc1002mangle(ses_init_buf->trailer.
2229 session_req.called_name,
2230 DEFAULT_CIFS_CALLED_NAME,
2231 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07002232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 /* calling name ends in null (byte 16) from old smb
2236 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002237 if (server->workstation_RFC1001_name &&
2238 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002239 rfc1002mangle(ses_init_buf->trailer.
2240 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002241 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05002242 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002243 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05002244 rfc1002mangle(ses_init_buf->trailer.
2245 session_req.calling_name,
2246 "LINUX_CIFS_CLNT",
2247 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 ses_init_buf->trailer.session_req.scope1 = 0;
2250 ses_init_buf->trailer.session_req.scope2 = 0;
2251 smb_buf = (struct smb_hdr *)ses_init_buf;
2252 /* sizeof RFC1002_SESSION_REQUEST with no scope */
2253 smb_buf->smb_buf_length = 0x81000044;
Jeff Layton0496e022008-12-30 12:39:16 -05002254 rc = smb_send(server, smb_buf, 0x44);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00002256 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00002257 requires very short break before negprot
2258 presumably because not expecting negprot
2259 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00002260 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00002261 complicating the code and causes no
2262 significant slowing down on mount
2263 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 }
Steve French50c2f752007-07-13 00:33:32 +00002265 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00002267
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
Steve French50c2f752007-07-13 00:33:32 +00002269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 return rc;
2271}
2272
2273static int
Jeff Laytond5c56052008-12-01 18:42:33 -05002274ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275{
2276 int rc = 0;
Steve French6a5fa2362010-01-01 01:28:43 +00002277 int val;
Jeff Laytond5c56052008-12-01 18:42:33 -05002278 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05002280 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
Jeff Laytond5c56052008-12-01 18:42:33 -05002282 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002283 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05002284 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002286 cERROR(1, "Error %d creating ipv6 socket", rc);
Jeff Laytond5c56052008-12-01 18:42:33 -05002287 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 }
Jeff Laytond5c56052008-12-01 18:42:33 -05002290
2291 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002292 cFYI(1, "ipv6 Socket created");
Jeff Laytond5c56052008-12-01 18:42:33 -05002293 server->ssocket = socket;
2294 socket->sk->sk_allocation = GFP_NOFS;
2295 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 }
2297
Ben Greear3eb9a882010-09-01 17:06:02 -07002298 rc = bind_socket(server);
2299 if (rc < 0)
2300 return rc;
2301
Jeff Laytond5c56052008-12-01 18:42:33 -05002302 /* user overrode default port */
2303 if (server->addr.sockAddr6.sin6_port) {
2304 rc = socket->ops->connect(socket,
2305 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002306 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002308 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00002309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002311 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00002312 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 later if fall back ports fail this time */
2314
Jeff Laytond5c56052008-12-01 18:42:33 -05002315 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05002317 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
2318 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
2319 rc = socket->ops->connect(socket, (struct sockaddr *)
2320 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002321 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002323 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
2325 }
2326 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05002327 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
2328 rc = socket->ops->connect(socket, (struct sockaddr *)
2329 &server->addr.sockAddr6,
2330 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00002331 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002332 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 }
2334
2335 /* give up here - unless we want to retry on different
2336 protocol families some day */
2337 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002338 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05002339 server->addr.sockAddr6.sin6_port = orig_port;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002340 cFYI(1, "Error %d connecting to server via ipv6", rc);
Jeff Laytond5c56052008-12-01 18:42:33 -05002341 sock_release(socket);
2342 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 return rc;
2344 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00002345
Jeff Laytond5c56052008-12-01 18:42:33 -05002346 /*
2347 * Eventually check for other socket options to change from
2348 * the default. sock_setsockopt not used because it expects
2349 * user space buffer
2350 */
2351 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002352 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002353
2354 if (server->tcp_nodelay) {
2355 val = 1;
2356 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
2357 (char *)&val, sizeof(val));
2358 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002359 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00002360 }
2361
Jeff Laytond5c56052008-12-01 18:42:33 -05002362 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00002363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 return rc;
2365}
2366
Steve French50c2f752007-07-13 00:33:32 +00002367void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
2368 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00002369{
2370 /* if we are reconnecting then should we check to see if
2371 * any requested capabilities changed locally e.g. via
2372 * remount but we can not do much about it here
2373 * if they have (even if we could detect it by the following)
2374 * Perhaps we could add a backpointer to array of sb from tcon
2375 * or if we change to make all sb to same share the same
2376 * sb as NFS - then we only have one backpointer to sb.
2377 * What if we wanted to mount the server share twice once with
2378 * and once without posixacls or posix paths? */
2379 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002380
Steve Frenchc18c8422007-07-18 23:21:09 +00002381 if (vol_info && vol_info->no_linux_ext) {
2382 tcon->fsUnixInfo.Capability = 0;
2383 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002384 cFYI(1, "Linux protocol extensions disabled");
Steve Frenchc18c8422007-07-18 23:21:09 +00002385 return;
2386 } else if (vol_info)
2387 tcon->unix_ext = 1; /* Unix Extensions supported */
2388
2389 if (tcon->unix_ext == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002390 cFYI(1, "Unix extensions disabled so not set on reconnect");
Steve Frenchc18c8422007-07-18 23:21:09 +00002391 return;
2392 }
Steve French50c2f752007-07-13 00:33:32 +00002393
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002394 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002395 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002396
Steve French8af18972007-02-14 04:42:51 +00002397 /* check for reconnect case in which we do not
2398 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002399 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002400 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00002401 originally at mount time */
2402 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2403 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002404 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2405 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002406 cERROR(1, "POSIXPATH support change");
Steve French8af18972007-02-14 04:42:51 +00002407 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002408 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002409 cERROR(1, "possible reconnect error");
2410 cERROR(1, "server disabled POSIX path support");
Igor Mammedov11b6d642008-02-15 19:06:04 +00002411 }
Steve French8af18972007-02-14 04:42:51 +00002412 }
Steve French50c2f752007-07-13 00:33:32 +00002413
Steve French8af18972007-02-14 04:42:51 +00002414 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002415 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002416 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002417 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002418 cFYI(1, "negotiated posix acl support");
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002419 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002420 sb->s_flags |= MS_POSIXACL;
2421 }
2422
Steve French75865f8c2007-06-24 18:30:48 +00002423 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002424 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002425 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002426 cFYI(1, "negotiate posix pathnames");
Steve French75865f8c2007-06-24 18:30:48 +00002427 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002428 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002429 CIFS_MOUNT_POSIX_PATHS;
2430 }
Steve French50c2f752007-07-13 00:33:32 +00002431
Steve French984acfe2007-04-26 16:42:50 +00002432 /* We might be setting the path sep back to a different
2433 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002434 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002435 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002436 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002437
2438 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2439 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2440 CIFS_SB(sb)->rsize = 127 * 1024;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002441 cFYI(DBG2, "larger reads not supported by srv");
Steve French75865f8c2007-06-24 18:30:48 +00002442 }
2443 }
Steve French50c2f752007-07-13 00:33:32 +00002444
2445
Joe Perchesb6b38f72010-04-21 03:50:45 +00002446 cFYI(1, "Negotiate caps 0x%x", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00002447#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002448 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002449 cFYI(1, "FCNTL cap");
Steve French75865f8c2007-06-24 18:30:48 +00002450 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002451 cFYI(1, "EXTATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00002452 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002453 cFYI(1, "POSIX path cap");
Steve French75865f8c2007-06-24 18:30:48 +00002454 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002455 cFYI(1, "XATTR cap");
Steve French75865f8c2007-06-24 18:30:48 +00002456 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002457 cFYI(1, "POSIX ACL cap");
Steve French75865f8c2007-06-24 18:30:48 +00002458 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002459 cFYI(1, "very large read cap");
Steve French75865f8c2007-06-24 18:30:48 +00002460 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002461 cFYI(1, "very large write cap");
Steve French8af18972007-02-14 04:42:51 +00002462#endif /* CIFS_DEBUG2 */
2463 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002464 if (vol_info == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002465 cFYI(1, "resetting capabilities failed");
Steve French442aa312007-09-24 20:25:46 +00002466 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002467 cERROR(1, "Negotiating Unix capabilities "
Steve French5a44b312007-09-20 15:16:24 +00002468 "with the server failed. Consider "
2469 "mounting with the Unix Extensions\n"
2470 "disabled, if problems are found, "
2471 "by specifying the nounix mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00002472 "option.");
Steve French5a44b312007-09-20 15:16:24 +00002473
Steve French8af18972007-02-14 04:42:51 +00002474 }
2475 }
2476}
2477
Steve French03a143c2008-02-14 06:38:30 +00002478static void
2479convert_delimiter(char *path, char delim)
2480{
2481 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002482 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002483
2484 if (path == NULL)
2485 return;
2486
Steve French582d21e2008-05-13 04:54:12 +00002487 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002488 old_delim = '\\';
2489 else
2490 old_delim = '/';
2491
Steve French03a143c2008-02-14 06:38:30 +00002492 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002493 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002494 path[i] = delim;
2495 }
2496}
2497
Steve French3b795212008-11-13 19:45:32 +00002498static void setup_cifs_sb(struct smb_vol *pvolume_info,
2499 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002500{
Jeff Layton2de970f2010-10-06 19:51:12 -04002501 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
2502
Steve French3b795212008-11-13 19:45:32 +00002503 if (pvolume_info->rsize > CIFSMaxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002504 cERROR(1, "rsize %d too large, using MaxBufSize",
2505 pvolume_info->rsize);
Steve French3b795212008-11-13 19:45:32 +00002506 cifs_sb->rsize = CIFSMaxBufSize;
2507 } else if ((pvolume_info->rsize) &&
2508 (pvolume_info->rsize <= CIFSMaxBufSize))
2509 cifs_sb->rsize = pvolume_info->rsize;
2510 else /* default */
2511 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002512
Steve French3b795212008-11-13 19:45:32 +00002513 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002514 cERROR(1, "wsize %d too large, using 4096 instead",
2515 pvolume_info->wsize);
Steve French3b795212008-11-13 19:45:32 +00002516 cifs_sb->wsize = 4096;
2517 } else if (pvolume_info->wsize)
2518 cifs_sb->wsize = pvolume_info->wsize;
2519 else
2520 cifs_sb->wsize = min_t(const int,
2521 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2522 127*1024);
2523 /* old default of CIFSMaxBufSize was too small now
2524 that SMB Write2 can send multiple pages in kvec.
2525 RFC1001 does not describe what happens when frame
2526 bigger than 128K is sent so use that as max in
2527 conjunction with 52K kvec constraint on arch with 4K
2528 page size */
2529
2530 if (cifs_sb->rsize < 2048) {
2531 cifs_sb->rsize = 2048;
2532 /* Windows ME may prefer this */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002533 cFYI(1, "readsize set to minimum: 2048");
Steve French3b795212008-11-13 19:45:32 +00002534 }
2535 /* calculate prepath */
2536 cifs_sb->prepath = pvolume_info->prepath;
2537 if (cifs_sb->prepath) {
2538 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2539 /* we can not convert the / to \ in the path
2540 separators in the prefixpath yet because we do not
2541 know (until reset_cifs_unix_caps is called later)
2542 whether POSIX PATH CAP is available. We normalize
2543 the / to \ after reset_cifs_unix_caps is called */
2544 pvolume_info->prepath = NULL;
2545 } else
2546 cifs_sb->prepathlen = 0;
2547 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2548 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2549 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2550 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002551 cFYI(1, "file mode: 0x%x dir mode: 0x%x",
2552 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
Steve French3b795212008-11-13 19:45:32 +00002553
2554 if (pvolume_info->noperm)
2555 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2556 if (pvolume_info->setuids)
2557 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2558 if (pvolume_info->server_ino)
2559 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2560 if (pvolume_info->remap)
2561 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2562 if (pvolume_info->no_xattr)
2563 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2564 if (pvolume_info->sfu_emul)
2565 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2566 if (pvolume_info->nobrl)
2567 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve Frenchbe652442009-02-23 15:21:59 +00002568 if (pvolume_info->nostrictsync)
Steve French4717bed2009-02-24 14:44:19 +00002569 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
Steve French13a6e422008-12-02 17:24:33 +00002570 if (pvolume_info->mand_lock)
2571 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002572 if (pvolume_info->cifs_acl)
2573 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2574 if (pvolume_info->override_uid)
2575 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2576 if (pvolume_info->override_gid)
2577 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2578 if (pvolume_info->dynperm)
2579 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05302580 if (pvolume_info->fsc)
2581 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
Jeff Layton0eb8a132010-10-06 19:51:12 -04002582 if (pvolume_info->multiuser)
2583 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
2584 CIFS_MOUNT_NO_PERM);
Steve French3b795212008-11-13 19:45:32 +00002585 if (pvolume_info->direct_io) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002586 cFYI(1, "mounting share using direct i/o");
Steve French3b795212008-11-13 19:45:32 +00002587 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2588 }
Stefan Metzmacher736a3322010-07-30 14:56:00 +02002589 if (pvolume_info->mfsymlinks) {
2590 if (pvolume_info->sfu_emul) {
2591 cERROR(1, "mount option mfsymlinks ignored if sfu "
2592 "mount option is used");
2593 } else {
2594 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
2595 }
2596 }
Steve French3b795212008-11-13 19:45:32 +00002597
2598 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
Joe Perchesb6b38f72010-04-21 03:50:45 +00002599 cERROR(1, "mount option dynperm ignored if cifsacl "
2600 "mount option supported");
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002601}
2602
Igor Mammedove4cce942009-02-10 14:10:26 +03002603static int
2604is_path_accessible(int xid, struct cifsTconInfo *tcon,
2605 struct cifs_sb_info *cifs_sb, const char *full_path)
2606{
2607 int rc;
Igor Mammedove4cce942009-02-10 14:10:26 +03002608 FILE_ALL_INFO *pfile_info;
2609
Igor Mammedove4cce942009-02-10 14:10:26 +03002610 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2611 if (pfile_info == NULL)
2612 return -ENOMEM;
2613
2614 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2615 0 /* not legacy */, cifs_sb->local_nls,
2616 cifs_sb->mnt_cifs_flags &
2617 CIFS_MOUNT_MAP_SPECIAL_CHR);
2618 kfree(pfile_info);
2619 return rc;
2620}
2621
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002622static void
2623cleanup_volume_info(struct smb_vol **pvolume_info)
2624{
2625 struct smb_vol *volume_info;
2626
Dan Carpenterad6cca62010-04-26 12:10:06 +02002627 if (!pvolume_info || !*pvolume_info)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002628 return;
2629
2630 volume_info = *pvolume_info;
2631 kzfree(volume_info->password);
2632 kfree(volume_info->UNC);
2633 kfree(volume_info->prepath);
2634 kfree(volume_info);
2635 *pvolume_info = NULL;
2636 return;
2637}
2638
Steve French2d6d5892009-04-09 00:36:44 +00002639#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002640/* build_path_to_root returns full path to root when
2641 * we do not have an exiting connection (tcon) */
2642static char *
2643build_unc_path_to_root(const struct smb_vol *volume_info,
2644 const struct cifs_sb_info *cifs_sb)
2645{
2646 char *full_path;
2647
2648 int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
2649 full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
2650 if (full_path == NULL)
2651 return ERR_PTR(-ENOMEM);
2652
2653 strncpy(full_path, volume_info->UNC, unc_len);
2654 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
2655 int i;
2656 for (i = 0; i < unc_len; i++) {
2657 if (full_path[i] == '\\')
2658 full_path[i] = '/';
2659 }
2660 }
2661
2662 if (cifs_sb->prepathlen)
2663 strncpy(full_path + unc_len, cifs_sb->prepath,
2664 cifs_sb->prepathlen);
2665
2666 full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
2667 return full_path;
2668}
Steve French2d6d5892009-04-09 00:36:44 +00002669#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671int
2672cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002673 char *mount_data_global, const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674{
Jeff Laytona2934c72009-12-03 08:09:41 -05002675 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002677 struct smb_vol *volume_info;
Jeff Laytona2934c72009-12-03 08:09:41 -05002678 struct cifsSesInfo *pSesInfo;
2679 struct cifsTconInfo *tcon;
2680 struct TCP_Server_Info *srvTcp;
Igor Mammedove4cce942009-02-10 14:10:26 +03002681 char *full_path;
Steve French2d6d5892009-04-09 00:36:44 +00002682 char *mount_data = mount_data_global;
Jeff Layton9d002df2010-10-06 19:51:11 -04002683 struct tcon_link *tlink;
Steve French2d6d5892009-04-09 00:36:44 +00002684#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002685 struct dfs_info3_param *referrals = NULL;
2686 unsigned int num_referrals = 0;
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002687 int referral_walks_count = 0;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002688try_mount_again:
Steve French2d6d5892009-04-09 00:36:44 +00002689#endif
Jeff Laytona2934c72009-12-03 08:09:41 -05002690 rc = 0;
2691 tcon = NULL;
2692 pSesInfo = NULL;
2693 srvTcp = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002694 full_path = NULL;
Jeff Layton9d002df2010-10-06 19:51:11 -04002695 tlink = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 xid = GetXid();
2698
Jeff Layton7586b762008-12-01 18:41:49 -05002699 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2700 if (!volume_info) {
2701 rc = -ENOMEM;
2702 goto out;
2703 }
Steve French50c2f752007-07-13 00:33:32 +00002704
Jeff Layton7586b762008-12-01 18:41:49 -05002705 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002706 rc = -EINVAL;
2707 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 }
2709
Jeff Layton7586b762008-12-01 18:41:49 -05002710 if (volume_info->nullauth) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002711 cFYI(1, "null user");
Jeff Layton7586b762008-12-01 18:41:49 -05002712 volume_info->username = "";
2713 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 /* BB fixme parse for domain name here */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002715 cFYI(1, "Username: %s", volume_info->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002717 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002718 /* In userspace mount helper we can get user name from alternate
2719 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002720 rc = -EINVAL;
2721 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 }
2723
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002725 if (volume_info->iocharset == NULL) {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002726 /* load_nls_default cannot return null */
2727 volume_info->local_nls = load_nls_default();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 } else {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002729 volume_info->local_nls = load_nls(volume_info->iocharset);
2730 if (volume_info->local_nls == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002731 cERROR(1, "CIFS mount error: iocharset %s not found",
2732 volume_info->iocharset);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002733 rc = -ELIBACC;
2734 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 }
2736 }
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002737 cifs_sb->local_nls = volume_info->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Jeff Layton63c038c2008-12-01 18:41:46 -05002739 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002740 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002741 if (IS_ERR(srvTcp)) {
2742 rc = PTR_ERR(srvTcp);
2743 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
2745
Jeff Layton36988c72010-04-24 07:57:43 -04002746 /* get a reference to a SMB session */
2747 pSesInfo = cifs_get_smb_ses(srvTcp, volume_info);
2748 if (IS_ERR(pSesInfo)) {
2749 rc = PTR_ERR(pSesInfo);
2750 pSesInfo = NULL;
2751 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 }
Steve French50c2f752007-07-13 00:33:32 +00002753
Jeff Laytond00c28d2010-04-24 07:57:44 -04002754 setup_cifs_sb(volume_info, cifs_sb);
2755 if (pSesInfo->capabilities & CAP_LARGE_FILES)
2756 sb->s_maxbytes = MAX_LFS_FILESIZE;
2757 else
2758 sb->s_maxbytes = MAX_NON_LFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Steve French8af18972007-02-14 04:42:51 +00002760 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 sb->s_time_gran = 100;
2762
Jeff Laytond00c28d2010-04-24 07:57:44 -04002763 /* search for existing tcon to this server share */
2764 tcon = cifs_get_tcon(pSesInfo, volume_info);
2765 if (IS_ERR(tcon)) {
2766 rc = PTR_ERR(tcon);
2767 tcon = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002768 goto remote_path_check;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002769 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002770
Steve Frenchd82c2df2008-11-15 00:07:26 +00002771 /* do not care if following two calls succeed - informational */
2772 if (!tcon->ipc) {
2773 CIFSSMBQFSDeviceInfo(xid, tcon);
2774 CIFSSMBQFSAttributeInfo(xid, tcon);
2775 }
2776
2777 /* tell server which Unix caps we support */
2778 if (tcon->ses->capabilities & CAP_UNIX)
2779 /* reset of caps checks mount to see if unix extensions
2780 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002781 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002782 else
2783 tcon->unix_ext = 0; /* server does not support them */
2784
2785 /* convert forward to back slashes in prepath here if needed */
2786 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2787 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2788
2789 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2790 cifs_sb->rsize = 1024 * 127;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002791 cFYI(DBG2, "no very large read support, rsize now 127K");
Steve Frenchd82c2df2008-11-15 00:07:26 +00002792 }
2793 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2794 cifs_sb->wsize = min(cifs_sb->wsize,
2795 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2796 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2797 cifs_sb->rsize = min(cifs_sb->rsize,
2798 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002800remote_path_check:
2801 /* check if a whole path (including prepath) is not remote */
2802 if (!rc && cifs_sb->prepathlen && tcon) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002803 /* build_path_to_root works only when we have a valid tcon */
2804 full_path = cifs_build_path_to_root(cifs_sb);
2805 if (full_path == NULL) {
2806 rc = -ENOMEM;
2807 goto mount_fail_check;
2808 }
2809 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002810 if (rc != -EREMOTE) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002811 kfree(full_path);
2812 goto mount_fail_check;
2813 }
2814 kfree(full_path);
2815 }
2816
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002817 /* get referral if needed */
2818 if (rc == -EREMOTE) {
Steve Frenchd036f502009-04-03 03:12:08 +00002819#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002820 if (referral_walks_count > MAX_NESTED_LINKS) {
2821 /*
2822 * BB: when we implement proper loop detection,
2823 * we will remove this check. But now we need it
2824 * to prevent an indefinite loop if 'DFS tree' is
2825 * misconfigured (i.e. has loops).
2826 */
2827 rc = -ELOOP;
2828 goto mount_fail_check;
2829 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002830 /* convert forward to back slashes in prepath here if needed */
2831 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2832 convert_delimiter(cifs_sb->prepath,
2833 CIFS_DIR_SEP(cifs_sb));
2834 full_path = build_unc_path_to_root(volume_info, cifs_sb);
2835 if (IS_ERR(full_path)) {
2836 rc = PTR_ERR(full_path);
2837 goto mount_fail_check;
2838 }
2839
Joe Perchesb6b38f72010-04-21 03:50:45 +00002840 cFYI(1, "Getting referral for: %s", full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002841 rc = get_dfs_path(xid, pSesInfo , full_path + 1,
2842 cifs_sb->local_nls, &num_referrals, &referrals,
2843 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
2844 if (!rc && num_referrals > 0) {
2845 char *fake_devname = NULL;
2846
2847 if (mount_data != mount_data_global)
2848 kfree(mount_data);
Jeff Layton7b91e262009-07-23 15:22:30 -04002849
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002850 mount_data = cifs_compose_mount_options(
2851 cifs_sb->mountdata, full_path + 1,
2852 referrals, &fake_devname);
Jeff Layton7b91e262009-07-23 15:22:30 -04002853
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002854 free_dfs_info_array(referrals, num_referrals);
Jeff Layton7b91e262009-07-23 15:22:30 -04002855 kfree(fake_devname);
2856 kfree(full_path);
2857
2858 if (IS_ERR(mount_data)) {
2859 rc = PTR_ERR(mount_data);
2860 mount_data = NULL;
2861 goto mount_fail_check;
2862 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002863
2864 if (tcon)
2865 cifs_put_tcon(tcon);
2866 else if (pSesInfo)
2867 cifs_put_smb_ses(pSesInfo);
2868
2869 cleanup_volume_info(&volume_info);
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002870 referral_walks_count++;
Jeff Laytona2934c72009-12-03 08:09:41 -05002871 FreeXid(xid);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002872 goto try_mount_again;
2873 }
Steve Frenchd036f502009-04-03 03:12:08 +00002874#else /* No DFS support, return error on mount */
2875 rc = -EOPNOTSUPP;
2876#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002877 }
2878
Jeff Layton9d002df2010-10-06 19:51:11 -04002879 if (rc)
2880 goto mount_fail_check;
2881
2882 /* now, hang the tcon off of the superblock */
2883 tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
2884 if (tlink == NULL) {
2885 rc = -ENOMEM;
2886 goto mount_fail_check;
2887 }
2888
2889 tlink->tl_index = pSesInfo->linux_uid;
2890 tlink->tl_tcon = tcon;
2891 tlink->tl_time = jiffies;
2892 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2893 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2894
2895 rc = radix_tree_preload(GFP_KERNEL);
2896 if (rc == -ENOMEM) {
2897 kfree(tlink);
2898 goto mount_fail_check;
2899 }
2900
2901 spin_lock(&cifs_sb->tlink_tree_lock);
2902 radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
2903 radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
2904 CIFS_TLINK_MASTER_TAG);
2905 spin_unlock(&cifs_sb->tlink_tree_lock);
2906 radix_tree_preload_end();
2907
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 Laytoncc20c032009-04-30 07:16:21 -04002949 int length, bytes_left;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 __u16 count;
2951
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 {
Steve French7c7b25b2006-06-01 19:20:10 +00002978 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_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 Pargaonkar5d0d2882010-10-13 18:15:00 -05002988 calc_lanman_hash(tcon->password, ses->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 Pargaonkar5d0d2882010-10-13 18:15:00 -05002994 SMBNTencrypt(tcon->password, ses->cryptKey, bcc_ptr);
Steve Frencheeac8042006-01-13 21:34:58 -08002995
Steve French7c7b25b2006-06-01 19:20:10 +00002996 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002997 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00002998 /* must align unicode strings */
2999 *bcc_ptr = 0; /* null byte password */
3000 bcc_ptr++;
3001 }
Steve Frencheeac8042006-01-13 21:34:58 -08003002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
Steve French50c2f752007-07-13 00:33:32 +00003004 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003005 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3007
3008 if (ses->capabilities & CAP_STATUS32) {
3009 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3010 }
3011 if (ses->capabilities & CAP_DFS) {
3012 smb_buffer->Flags2 |= SMBFLG2_DFS;
3013 }
3014 if (ses->capabilities & CAP_UNICODE) {
3015 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3016 length =
Steve French50c2f752007-07-13 00:33:32 +00003017 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3018 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003019 (/* server len*/ + 256 /* share len */), nls_codepage);
3020 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 bcc_ptr += 2; /* skip trailing null */
3022 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 strcpy(bcc_ptr, tree);
3024 bcc_ptr += strlen(tree) + 1;
3025 }
3026 strcpy(bcc_ptr, "?????");
3027 bcc_ptr += strlen("?????");
3028 bcc_ptr += 1;
3029 count = bcc_ptr - &pSMB->Password[0];
3030 pSMB->hdr.smb_buf_length += count;
3031 pSMB->ByteCount = cpu_to_le16(count);
3032
Steve French133672e2007-11-13 22:41:37 +00003033 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3034 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 /* above now done in SendReceive */
3037 if ((rc == 0) && (tcon != NULL)) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003038 bool is_unicode;
3039
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003041 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 tcon->tid = smb_buffer_response->Tid;
3043 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003044 bytes_left = BCC(smb_buffer_response);
3045 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003046 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3047 is_unicode = true;
3048 else
3049 is_unicode = false;
3050
Jeff Laytoncc20c032009-04-30 07:16:21 -04003051
Steve French50c2f752007-07-13 00:33:32 +00003052 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003053 if (length == 3) {
3054 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3055 (bcc_ptr[2] == 'C')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003056 cFYI(1, "IPC connection");
Steve French7f8ed422007-09-28 22:28:55 +00003057 tcon->ipc = 1;
3058 }
3059 } else if (length == 2) {
3060 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3061 /* the most common case */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003062 cFYI(1, "disk share connection");
Steve French7f8ed422007-09-28 22:28:55 +00003063 }
3064 }
Steve French50c2f752007-07-13 00:33:32 +00003065 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003066 bytes_left -= (length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003068
3069 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003070 kfree(tcon->nativeFileSystem);
Steve Frenchd185cda2009-04-30 17:45:10 +00003071 tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003072 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003073 nls_codepage);
3074
Joe Perchesb6b38f72010-04-21 03:50:45 +00003075 cFYI(1, "nativeFileSystem=%s", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003076
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003077 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003078 (smb_buffer_response->WordCount == 7))
3079 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003080 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3081 else
3082 tcon->Flags = 0;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003083 cFYI(1, "Tcon flags: 0x%x ", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003085 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 ses->ipc_tid = smb_buffer_response->Tid;
3087 }
3088
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003089 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 return rc;
3091}
3092
3093int
3094cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3095{
Jeff Layton9d002df2010-10-06 19:51:11 -04003096 int i, ret;
Steve French50c2f752007-07-13 00:33:32 +00003097 char *tmp;
Jeff Layton9d002df2010-10-06 19:51:11 -04003098 struct tcon_link *tlink[8];
3099 unsigned long index = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Jeff Layton2de970f2010-10-06 19:51:12 -04003101 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3102
Jeff Layton9d002df2010-10-06 19:51:11 -04003103 do {
3104 spin_lock(&cifs_sb->tlink_tree_lock);
3105 ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
3106 (void **)tlink, index,
3107 ARRAY_SIZE(tlink));
3108 /* increment index for next pass */
3109 if (ret > 0)
3110 index = tlink[ret - 1]->tl_index + 1;
3111 for (i = 0; i < ret; i++) {
3112 cifs_get_tlink(tlink[i]);
3113 clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
3114 radix_tree_delete(&cifs_sb->tlink_tree,
3115 tlink[i]->tl_index);
3116 }
3117 spin_unlock(&cifs_sb->tlink_tree_lock);
Steve French50c2f752007-07-13 00:33:32 +00003118
Jeff Layton9d002df2010-10-06 19:51:11 -04003119 for (i = 0; i < ret; i++)
3120 cifs_put_tlink(tlink[i]);
3121 } while (ret != 0);
3122
Steve French2fe87f02006-09-21 07:02:52 +00003123 tmp = cifs_sb->prepath;
3124 cifs_sb->prepathlen = 0;
3125 cifs_sb->prepath = NULL;
3126 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
Jeff Layton9d002df2010-10-06 19:51:11 -04003128 return 0;
Steve French50c2f752007-07-13 00:33:32 +00003129}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Jeff Layton198b5682010-04-24 07:57:48 -04003131int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132{
3133 int rc = 0;
Jeff Layton198b5682010-04-24 07:57:48 -04003134 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
Jeff Layton198b5682010-04-24 07:57:48 -04003136 /* only send once per connect */
3137 if (server->maxBuf != 0)
3138 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
Jeff Layton198b5682010-04-24 07:57:48 -04003140 rc = CIFSSMBNegotiate(xid, ses);
3141 if (rc == -EAGAIN) {
3142 /* retry only once on 1st time connection */
3143 rc = CIFSSMBNegotiate(xid, ses);
3144 if (rc == -EAGAIN)
3145 rc = -EHOSTDOWN;
3146 }
3147 if (rc == 0) {
3148 spin_lock(&GlobalMid_Lock);
3149 if (server->tcpStatus != CifsExiting)
3150 server->tcpStatus = CifsGood;
3151 else
3152 rc = -EHOSTDOWN;
3153 spin_unlock(&GlobalMid_Lock);
3154
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 }
Steve French26b994f2008-08-06 05:11:33 +00003156
Jeff Layton198b5682010-04-24 07:57:48 -04003157 return rc;
3158}
Steve French26b994f2008-08-06 05:11:33 +00003159
Jeff Layton198b5682010-04-24 07:57:48 -04003160
3161int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
3162 struct nls_table *nls_info)
3163{
3164 int rc = 0;
3165 struct TCP_Server_Info *server = ses->server;
3166
3167 ses->flags = 0;
3168 ses->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003169 if (linuxExtEnabled == 0)
Jeff Layton198b5682010-04-24 07:57:48 -04003170 ses->capabilities &= (~CAP_UNIX);
Steve French20418ac2009-04-30 16:13:32 +00003171
Joe Perchesb6b38f72010-04-21 03:50:45 +00003172 cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
3173 server->secMode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003174
Jeff Layton198b5682010-04-24 07:57:48 -04003175 rc = CIFS_SessSetup(xid, ses, nls_info);
Steve French26b994f2008-08-06 05:11:33 +00003176 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003177 cERROR(1, "Send error in SessSetup = %d", rc);
Steve French26b994f2008-08-06 05:11:33 +00003178 } else {
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05003179 mutex_lock(&ses->server->srv_mutex);
3180 if (!server->session_estab) {
3181 memcpy(&server->session_key.data,
3182 &ses->auth_key.data, ses->auth_key.len);
3183 server->session_key.len = ses->auth_key.len;
3184 ses->server->session_estab = true;
3185 }
3186 mutex_unlock(&server->srv_mutex);
3187
Joe Perchesb6b38f72010-04-21 03:50:45 +00003188 cFYI(1, "CIFS Session Established successfully");
Steve French20418ac2009-04-30 16:13:32 +00003189 spin_lock(&GlobalMid_Lock);
Jeff Layton198b5682010-04-24 07:57:48 -04003190 ses->status = CifsGood;
3191 ses->need_reconnect = false;
Steve French20418ac2009-04-30 16:13:32 +00003192 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003193 }
3194
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 return rc;
3196}
3197
Steve Frenchd2445552010-10-08 03:38:46 +00003198static struct cifsTconInfo *
Jeff Layton9d002df2010-10-06 19:51:11 -04003199cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
3200{
3201 struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
3202 struct cifsSesInfo *ses;
3203 struct cifsTconInfo *tcon = NULL;
3204 struct smb_vol *vol_info;
3205 char username[MAX_USERNAME_SIZE + 1];
3206
3207 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
3208 if (vol_info == NULL) {
3209 tcon = ERR_PTR(-ENOMEM);
3210 goto out;
3211 }
3212
3213 snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
3214 vol_info->username = username;
3215 vol_info->local_nls = cifs_sb->local_nls;
3216 vol_info->linux_uid = fsuid;
3217 vol_info->cred_uid = fsuid;
3218 vol_info->UNC = master_tcon->treeName;
3219 vol_info->retry = master_tcon->retry;
3220 vol_info->nocase = master_tcon->nocase;
3221 vol_info->local_lease = master_tcon->local_lease;
3222 vol_info->no_linux_ext = !master_tcon->unix_ext;
3223
3224 /* FIXME: allow for other secFlg settings */
3225 vol_info->secFlg = CIFSSEC_MUST_KRB5;
3226
3227 /* get a reference for the same TCP session */
3228 write_lock(&cifs_tcp_ses_lock);
3229 ++master_tcon->ses->server->srv_count;
3230 write_unlock(&cifs_tcp_ses_lock);
3231
3232 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
3233 if (IS_ERR(ses)) {
3234 tcon = (struct cifsTconInfo *)ses;
3235 cifs_put_tcp_session(master_tcon->ses->server);
3236 goto out;
3237 }
3238
3239 tcon = cifs_get_tcon(ses, vol_info);
3240 if (IS_ERR(tcon)) {
3241 cifs_put_smb_ses(ses);
3242 goto out;
3243 }
3244
3245 if (ses->capabilities & CAP_UNIX)
3246 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
3247out:
3248 kfree(vol_info);
3249
3250 return tcon;
3251}
3252
3253static struct tcon_link *
3254cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
3255{
3256 struct tcon_link *tlink;
3257 unsigned int ret;
3258
3259 spin_lock(&cifs_sb->tlink_tree_lock);
3260 ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
3261 0, 1, CIFS_TLINK_MASTER_TAG);
3262 spin_unlock(&cifs_sb->tlink_tree_lock);
3263
3264 /* the master tcon should always be present */
3265 if (ret == 0)
3266 BUG();
3267
3268 return tlink;
3269}
3270
3271struct cifsTconInfo *
3272cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3273{
3274 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3275}
3276
3277static int
3278cifs_sb_tcon_pending_wait(void *unused)
3279{
3280 schedule();
3281 return signal_pending(current) ? -ERESTARTSYS : 0;
3282}
3283
3284/*
3285 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3286 * current task.
3287 *
3288 * If the superblock doesn't refer to a multiuser mount, then just return
3289 * the master tcon for the mount.
3290 *
3291 * First, search the radix tree for an existing tcon for this fsuid. If one
3292 * exists, then check to see if it's pending construction. If it is then wait
3293 * for construction to complete. Once it's no longer pending, check to see if
3294 * it failed and either return an error or retry construction, depending on
3295 * the timeout.
3296 *
3297 * If one doesn't exist then insert a new tcon_link struct into the tree and
3298 * try to construct a new one.
3299 */
3300struct tcon_link *
3301cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
3302{
3303 int ret;
3304 unsigned long fsuid = (unsigned long) current_fsuid();
3305 struct tcon_link *tlink, *newtlink;
3306
3307 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
3308 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3309
3310 spin_lock(&cifs_sb->tlink_tree_lock);
3311 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3312 if (tlink)
3313 cifs_get_tlink(tlink);
3314 spin_unlock(&cifs_sb->tlink_tree_lock);
3315
3316 if (tlink == NULL) {
3317 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
3318 if (newtlink == NULL)
3319 return ERR_PTR(-ENOMEM);
3320 newtlink->tl_index = fsuid;
3321 newtlink->tl_tcon = ERR_PTR(-EACCES);
3322 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
3323 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
3324 cifs_get_tlink(newtlink);
3325
3326 ret = radix_tree_preload(GFP_KERNEL);
3327 if (ret != 0) {
3328 kfree(newtlink);
3329 return ERR_PTR(ret);
3330 }
3331
3332 spin_lock(&cifs_sb->tlink_tree_lock);
3333 /* was one inserted after previous search? */
3334 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3335 if (tlink) {
3336 cifs_get_tlink(tlink);
3337 spin_unlock(&cifs_sb->tlink_tree_lock);
3338 radix_tree_preload_end();
3339 kfree(newtlink);
3340 goto wait_for_construction;
3341 }
3342 ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
3343 spin_unlock(&cifs_sb->tlink_tree_lock);
3344 radix_tree_preload_end();
3345 if (ret) {
3346 kfree(newtlink);
3347 return ERR_PTR(ret);
3348 }
3349 tlink = newtlink;
3350 } else {
3351wait_for_construction:
3352 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
3353 cifs_sb_tcon_pending_wait,
3354 TASK_INTERRUPTIBLE);
3355 if (ret) {
3356 cifs_put_tlink(tlink);
3357 return ERR_PTR(ret);
3358 }
3359
3360 /* if it's good, return it */
3361 if (!IS_ERR(tlink->tl_tcon))
3362 return tlink;
3363
3364 /* return error if we tried this already recently */
3365 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
3366 cifs_put_tlink(tlink);
3367 return ERR_PTR(-EACCES);
3368 }
3369
3370 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
3371 goto wait_for_construction;
3372 }
3373
3374 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
3375 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
3376 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
3377
3378 if (IS_ERR(tlink->tl_tcon)) {
3379 cifs_put_tlink(tlink);
3380 return ERR_PTR(-EACCES);
3381 }
3382
3383 return tlink;
3384}
Jeff Layton2de970f2010-10-06 19:51:12 -04003385
3386/*
3387 * periodic workqueue job that scans tcon_tree for a superblock and closes
3388 * out tcons.
3389 */
3390static void
3391cifs_prune_tlinks(struct work_struct *work)
3392{
3393 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
3394 prune_tlinks.work);
3395 struct tcon_link *tlink[8];
3396 unsigned long now = jiffies;
3397 unsigned long index = 0;
3398 int i, ret;
3399
3400 do {
3401 spin_lock(&cifs_sb->tlink_tree_lock);
3402 ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
3403 (void **)tlink, index,
3404 ARRAY_SIZE(tlink));
3405 /* increment index for next pass */
3406 if (ret > 0)
3407 index = tlink[ret - 1]->tl_index + 1;
3408 for (i = 0; i < ret; i++) {
3409 if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
3410 atomic_read(&tlink[i]->tl_count) != 0 ||
3411 time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
3412 now)) {
3413 tlink[i] = NULL;
3414 continue;
3415 }
3416 cifs_get_tlink(tlink[i]);
3417 clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
3418 radix_tree_delete(&cifs_sb->tlink_tree,
3419 tlink[i]->tl_index);
3420 }
3421 spin_unlock(&cifs_sb->tlink_tree_lock);
3422
3423 for (i = 0; i < ret; i++) {
3424 if (tlink[i] != NULL)
3425 cifs_put_tlink(tlink[i]);
3426 }
3427 } while (ret != 0);
3428
3429 queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
3430 TLINK_IDLE_EXPIRE);
3431}