blob: 3156a9de947da36f2a5a417123880d5b02dce043 [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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 unsigned int rsize;
104 unsigned int wsize;
Steve French6a5fa2362010-01-01 01:28:43 +0000105 bool sockopt_tcp_nodelay:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000107 char *prepath;
Ben Greear3eb9a882010-09-01 17:06:02 -0700108 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
Jeff Laytona5fc4ce2010-04-24 07:57:42 -0400109 struct nls_table *local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110};
111
Jeff Layton9d002df2010-10-06 19:51:11 -0400112#define TLINK_ERROR_EXPIRE (1 * HZ)
113
114
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500115static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500116static int ipv6_connect(struct TCP_Server_Info *server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Jeff Laytond5c56052008-12-01 18:42:33 -0500118/*
119 * cifs tcp session reconnection
120 *
121 * mark tcp session as reconnecting so temporarily locked
122 * mark all smb sessions as reconnecting for tcp session
123 * reconnect tcp session
124 * wake up waiters on reconnection? - (not needed currently)
125 */
Steve French2cd646a2006-09-28 19:43:08 +0000126static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127cifs_reconnect(struct TCP_Server_Info *server)
128{
129 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500130 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 struct cifsSesInfo *ses;
132 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000133 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000136 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000137 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 next time through the loop */
139 spin_unlock(&GlobalMid_Lock);
140 return rc;
141 } else
142 server->tcpStatus = CifsNeedReconnect;
143 spin_unlock(&GlobalMid_Lock);
144 server->maxBuf = 0;
145
Joe Perchesb6b38f72010-04-21 03:50:45 +0000146 cFYI(1, "Reconnecting tcp session");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 /* before reconnecting the tcp session, mark the smb session (uid)
149 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500150 read_lock(&cifs_tcp_ses_lock);
151 list_for_each(tmp, &server->smb_ses_list) {
152 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
153 ses->need_reconnect = true;
154 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500155 list_for_each(tmp2, &ses->tcon_list) {
156 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
157 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500160 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500162 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000163 if (server->ssocket) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000164 cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
165 server->ssocket->flags);
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800166 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000167 cFYI(1, "Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000168 server->ssocket->state,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000169 server->ssocket->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 sock_release(server->ssocket);
171 server->ssocket = NULL;
172 }
173
174 spin_lock(&GlobalMid_Lock);
175 list_for_each(tmp, &server->pending_mid_q) {
176 mid_entry = list_entry(tmp, struct
177 mid_q_entry,
178 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000179 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700180 /* Mark other intransit requests as needing
181 retry so we do not immediately mark the
182 session bad again (ie after we reconnect
183 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000184 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
186 }
187 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500188 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Jeff Layton469ee612008-10-16 18:46:39 +0000190 while ((server->tcpStatus != CifsExiting) &&
191 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000192 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500193 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500194 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500195 else
196 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000197 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000198 cFYI(1, "reconnect error %d", rc);
Steve French0cb766a2005-04-28 22:41:11 -0700199 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 } else {
201 atomic_inc(&tcpSesReconnectCount);
202 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000203 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700205 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000206 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 /* atomic_set(&server->inFlight,0);*/
208 wake_up(&server->response_q);
209 }
210 }
211 return rc;
212}
213
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000214/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700215 return codes:
216 0 not a transact2, or all data present
217 >0 transact2 with that much data missing
218 -EINVAL = invalid transact2
219
220 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000221static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700222{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000223 struct smb_t2_rsp *pSMBt;
224 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700225 int data_in_this_rsp;
226 int remaining;
227
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000228 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700229 return 0;
230
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000231 /* check for plausible wct, bcc and t2 data and parm sizes */
232 /* check for parm and data offset going beyond end of smb */
233 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000234 cFYI(1, "invalid transact2 word count");
Steve Frenche4eb2952005-04-28 22:41:09 -0700235 return -EINVAL;
236 }
237
238 pSMBt = (struct smb_t2_rsp *)pSMB;
239
240 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
241 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
242
243 remaining = total_data_size - data_in_this_rsp;
244
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000245 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700246 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000247 else if (remaining < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000248 cFYI(1, "total data %d smaller than data in frame %d",
249 total_data_size, data_in_this_rsp);
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 return -EINVAL;
251 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000252 cFYI(1, "missing %d bytes from transact2, check next response",
253 remaining);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000254 if (total_data_size > maxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000255 cERROR(1, "TotalDataSize %d is over maximum buffer %d",
256 total_data_size, maxBufSize);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000257 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700258 }
259 return remaining;
260 }
261}
262
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000263static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700264{
265 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
266 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
267 int total_data_size;
268 int total_in_buf;
269 int remaining;
270 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000271 char *data_area_of_target;
272 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700273 __u16 byte_count;
274
275 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
276
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000277 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000278 cFYI(1, "total data size of primary and secondary t2 differ");
Steve Frenche4eb2952005-04-28 22:41:09 -0700279 }
280
281 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
282
283 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000284
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000285 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700286 return -EINVAL;
287
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000288 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700289 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000290
Steve Frenche4eb2952005-04-28 22:41:09 -0700291 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 if (remaining < total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000293 cFYI(1, "transact2 2nd response contains too much data");
Steve Frenche4eb2952005-04-28 22:41:09 -0700294 }
295
296 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000297 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
299 /* validate target area */
300
301 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000302 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700303
304 data_area_of_target += total_in_buf;
305
306 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000307 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700308 total_in_buf += total_in_buf2;
309 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
310 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
311 byte_count += total_in_buf2;
312 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
313
Steve French70ca7342005-09-22 16:32:06 -0700314 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700315 byte_count += total_in_buf2;
316
317 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000318
Steve French70ca7342005-09-22 16:32:06 -0700319 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700320
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000321 if (remaining == total_in_buf2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000322 cFYI(1, "found the last secondary response");
Steve Frenche4eb2952005-04-28 22:41:09 -0700323 return 0; /* we are done */
324 } else /* more responses to go */
325 return 1;
326
327}
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static int
330cifs_demultiplex_thread(struct TCP_Server_Info *server)
331{
332 int length;
333 unsigned int pdu_length, total_read;
334 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700335 struct smb_hdr *bigbuf = NULL;
336 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 struct msghdr smb_msg;
338 struct kvec iov;
339 struct socket *csocket = server->ssocket;
340 struct list_head *tmp;
341 struct cifsSesInfo *ses;
342 struct task_struct *task_to_wake = NULL;
343 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700344 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000345 bool isLargeBuf = false;
346 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700347 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 current->flags |= PF_MEMALLOC;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000350 cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400351
352 length = atomic_inc_return(&tcpSesAllocCount);
353 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000354 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
355 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700357 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000358 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700359 if (try_to_freeze())
360 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700361 if (bigbuf == NULL) {
362 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000363 if (!bigbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000364 cERROR(1, "No memory for large SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700365 msleep(3000);
366 /* retry will check if exiting */
367 continue;
368 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000369 } else if (isLargeBuf) {
370 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000371 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700373
374 if (smallbuf == NULL) {
375 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000376 if (!smallbuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000377 cERROR(1, "No memory for SMB response");
Steve Frenchb8643e12005-04-28 22:41:07 -0700378 msleep(1000);
379 /* retry will check if exiting */
380 continue;
381 }
382 /* beginning of smb buffer is cleared in our buf_get */
383 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000384 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700385
Steve French4b18f2a2008-04-29 00:06:05 +0000386 isLargeBuf = false;
387 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700388 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 iov.iov_base = smb_buffer;
390 iov.iov_len = 4;
391 smb_msg.msg_control = NULL;
392 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000393 pdu_length = 4; /* enough to get RFC1001 header */
394incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 length =
396 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000397 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jeff Layton469ee612008-10-16 18:46:39 +0000399 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 break;
401 } else if (server->tcpStatus == CifsNeedReconnect) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000402 cFYI(1, "Reconnect after server stopped responding");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 cifs_reconnect(server);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000404 cFYI(1, "call to reconnect done");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 csocket = server->ssocket;
406 continue;
Jeff Layton522bbe62010-09-03 12:00:49 -0400407 } else if (length == -ERESTARTSYS ||
408 length == -EAGAIN ||
409 length == -EINTR) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700410 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 allowing socket to clear and app threads to set
412 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000413 if (pdu_length < 4) {
414 iov.iov_base = (4 - pdu_length) +
415 (char *)smb_buffer;
416 iov.iov_len = pdu_length;
417 smb_msg.msg_control = NULL;
418 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000419 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000420 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000421 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000423 cFYI(1, "Reconnect after unexpected peek error %d",
424 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 cifs_reconnect(server);
426 csocket = server->ssocket;
427 wake_up(&server->response_q);
428 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000429 } else if (length < pdu_length) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000430 cFYI(1, "requested %d bytes but only got %d bytes",
431 pdu_length, length);
Steve Frenchf01d5e12007-08-30 21:13:31 +0000432 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000433 msleep(1);
434 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Steve French67010fb2005-04-28 22:41:09 -0700436
Steve French70ca7342005-09-22 16:32:06 -0700437 /* The right amount was read from socket - 4 bytes */
438 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* the first byte big endian of the length field,
441 is actually not part of the length but the type
442 with the most common, zero, as regular data */
443 temp = *((char *) smb_buffer);
444
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000445 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700446 but we convert it here so it is always manipulated
447 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700448 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700449 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700450
Joe Perchesb6b38f72010-04-21 03:50:45 +0000451 cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
Steve French70ca7342005-09-22 16:32:06 -0700452
453 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 continue;
Steve French70ca7342005-09-22 16:32:06 -0700455 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000456 cFYI(1, "Good RFC 1002 session rsp");
Steve Frenche4eb2952005-04-28 22:41:09 -0700457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700460 an error on SMB negprot response */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000461 cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
462 pdu_length);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400463 /* give server a second to clean up */
464 msleep(1000);
465 /* always try 445 first on reconnect since we get NACK
466 * on some if we ever connected to port 139 (the NACK
467 * is since we do not begin with RFC1001 session
468 * initialize frame)
469 */
Jeff Layton32670392010-09-03 12:00:50 -0400470 cifs_set_port((struct sockaddr *)
471 &server->addr.sockAddr, CIFS_PORT);
Jeff Layton7332f2a2010-09-03 12:00:49 -0400472 cifs_reconnect(server);
473 csocket = server->ssocket;
474 wake_up(&server->response_q);
475 continue;
Steve French70ca7342005-09-22 16:32:06 -0700476 } else if (temp != (char) 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000477 cERROR(1, "Unknown RFC 1002 frame");
Steve French70ca7342005-09-22 16:32:06 -0700478 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
479 length);
Steve French46810cb2005-04-28 22:41:09 -0700480 cifs_reconnect(server);
481 csocket = server->ssocket;
482 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700483 }
484
485 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000487 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000488 cERROR(1, "Invalid size SMB length %d pdu_length %d",
489 length, pdu_length+4);
Steve Frenche4eb2952005-04-28 22:41:09 -0700490 cifs_reconnect(server);
491 csocket = server->ssocket;
492 wake_up(&server->response_q);
493 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700495
496 /* else length ok */
497 reconnect = 0;
498
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000499 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000500 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 memcpy(bigbuf, smallbuf, 4);
502 smb_buffer = bigbuf;
503 }
504 length = 0;
505 iov.iov_base = 4 + (char *)smb_buffer;
506 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000507 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 total_read += length) {
509 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
510 pdu_length - total_read, 0);
Jeff Layton522bbe62010-09-03 12:00:49 -0400511 if (server->tcpStatus == CifsExiting) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 /* then will exit */
513 reconnect = 2;
514 break;
515 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700516 cifs_reconnect(server);
517 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000518 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 /* Now we will reread sock */
520 reconnect = 1;
521 break;
Jeff Layton522bbe62010-09-03 12:00:49 -0400522 } else if (length == -ERESTARTSYS ||
523 length == -EAGAIN ||
524 length == -EINTR) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700527 threads to set tcpStatus
528 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000529 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700530 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 } else if (length <= 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cERROR(1, "Received no data, expecting %d",
533 pdu_length - total_read);
Steve Frenche4eb2952005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
536 reconnect = 1;
537 break;
Steve French46810cb2005-04-28 22:41:09 -0700538 }
539 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000542 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700543 continue;
544
545 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000546
Steve Frenche4eb2952005-04-28 22:41:09 -0700547
548 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000549 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700550 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 continue;
552 }
553
554
555 task_to_wake = NULL;
556 spin_lock(&GlobalMid_Lock);
557 list_for_each(tmp, &server->pending_mid_q) {
558 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
559
Steve French50c2f752007-07-13 00:33:32 +0000560 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
562 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000563 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700564 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000565 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000566 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000568 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000570 mid_entry->multiRsp =
571 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700572 break;
573 } else {
574 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000575 mid_entry->multiEnd =
576 true;
Steve French50c2f752007-07-13 00:33:32 +0000577 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 }
579 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (!isLargeBuf) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000581 cERROR(1, "1st trans2 resp needs bigbuf");
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000583 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700585 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 mid_entry->resp_buf =
587 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000588 mid_entry->largeBuf =
589 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700590 bigbuf = NULL;
591 }
592 }
593 break;
Steve French50c2f752007-07-13 00:33:32 +0000594 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000596 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700597multi_t2_fnd:
598 task_to_wake = mid_entry->tsk;
599 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700600#ifdef CONFIG_CIFS_STATS2
601 mid_entry->when_received = jiffies;
602#endif
Steve French3a5ff612006-07-14 22:37:11 +0000603 /* so we do not time out requests to server
604 which is still responding (since server could
605 be busy but not dead) */
606 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 break;
608 }
609 }
610 spin_unlock(&GlobalMid_Lock);
611 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700612 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700614 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000615 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700616 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000617 else
Steve Frenchcd634992005-04-28 22:41:10 -0700618 smallbuf = NULL;
619 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700620 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000621 } else if (!is_valid_oplock_break(smb_buffer, server) &&
622 !isMultiRsp) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000623 cERROR(1, "No task to wake, unknown frame received! "
624 "NumMids %d", midCount.counter);
Steve French50c2f752007-07-13 00:33:32 +0000625 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700626 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000627#ifdef CONFIG_CIFS_DEBUG2
628 cifs_dump_detail(smb_buffer);
629 cifs_dump_mids(server);
630#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000631
Steve Frenche4eb2952005-04-28 22:41:09 -0700632 }
633 } /* end while !EXITING */
634
Jeff Laytone7ddee92008-11-14 13:44:38 -0500635 /* take it off the list, if it's not already */
636 write_lock(&cifs_tcp_ses_lock);
637 list_del_init(&server->tcp_ses_list);
638 write_unlock(&cifs_tcp_ses_lock);
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 spin_lock(&GlobalMid_Lock);
641 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000642 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000643 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000644
Steve French31ca3bc2005-04-28 22:41:11 -0700645 /* check if we have blocked requests that need to free */
646 /* Note that cifs_max_pending is normally 50, but
647 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000648 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000649 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700650 atomic_set(&server->inFlight, cifs_max_pending - 1);
651 /* We do not want to set the max_pending too low or we
652 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000654 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700656 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 to the same server - they now will see the session is in exit state
658 and get out of SendReceive. */
659 wake_up_all(&server->request_q);
660 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700661 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000662
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000663 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 sock_release(csocket);
665 server->ssocket = NULL;
666 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700667 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000668 cifs_buf_release(bigbuf);
669 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Jeff Layton14fbf502008-11-14 13:53:46 -0500672 /*
673 * BB: we shouldn't have to do any of this. It shouldn't be
674 * possible to exit from the thread with active SMB sessions
675 */
676 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700678 /* loop through server session structures attached to this and
679 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500680 list_for_each(tmp, &server->smb_ses_list) {
681 ses = list_entry(tmp, struct cifsSesInfo,
682 smb_ses_list);
683 ses->status = CifsExiting;
684 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500686 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700688 /* although we can not zero the server struct pointer yet,
689 since there are active requests which may depnd on them,
690 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500691 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700692 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500693 smb_ses_list);
694 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700695 }
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 spin_lock(&GlobalMid_Lock);
698 list_for_each(tmp, &server->pending_mid_q) {
699 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
700 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "Clearing Mid 0x%x - waking up ",
702 mid_entry->mid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000704 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
707 }
708 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500709 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700711 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 }
713
Steve Frenchf1914012005-08-18 09:37:34 -0700714 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000715 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700717 /* due to delays on oplock break requests, we need
718 to wait at least 45 seconds before giving up
719 on a request getting a response and going ahead
720 and killing cifsd */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000721 cFYI(1, "Wait for exit from demultiplex thread");
Steve French31ca3bc2005-04-28 22:41:11 -0700722 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* if threads still have not exited they are probably never
724 coming home not much else we can do but free the memory */
725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Steve French31ca3bc2005-04-28 22:41:11 -0700727 /* last chance to mark ses pointers invalid
728 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000729 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700730 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500731 /* BB: This shouldn't be necessary, see above */
732 read_lock(&cifs_tcp_ses_lock);
733 list_for_each(tmp, &server->smb_ses_list) {
734 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
735 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700736 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500737 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700738
Jeff Laytonc359cf32007-11-16 22:22:06 +0000739 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400740 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700741 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400742
743 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000744 if (length > 0)
745 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
746 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000747
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400748 /* if server->tsk was NULL then wait for a signal before exiting */
749 if (!task_to_wake) {
750 set_current_state(TASK_INTERRUPTIBLE);
751 while (!signal_pending(current)) {
752 schedule();
753 set_current_state(TASK_INTERRUPTIBLE);
754 }
755 set_current_state(TASK_RUNNING);
756 }
757
Jeff Layton0468a2c2008-12-01 07:09:35 -0500758 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
Jeff Laytonc359cf32007-11-16 22:22:06 +0000761/* extract the host portion of the UNC string */
762static char *
763extract_hostname(const char *unc)
764{
765 const char *src;
766 char *dst, *delim;
767 unsigned int len;
768
769 /* skip double chars at beginning of string */
770 /* BB: check validity of these bytes? */
771 src = unc + 2;
772
773 /* delimiter between hostname and sharename is always '\\' now */
774 delim = strchr(src, '\\');
775 if (!delim)
776 return ERR_PTR(-EINVAL);
777
778 len = delim - src;
779 dst = kmalloc((len + 1), GFP_KERNEL);
780 if (dst == NULL)
781 return ERR_PTR(-ENOMEM);
782
783 memcpy(dst, src, len);
784 dst[len] = '\0';
785
786 return dst;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int
Steve French50c2f752007-07-13 00:33:32 +0000790cifs_parse_mount_options(char *options, const char *devname,
791 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 char *value;
794 char *data;
795 unsigned int temp_len, i, j;
796 char separator[2];
Jeff Layton9b9d6b242009-07-31 06:56:09 -0400797 short int override_uid = -1;
798 short int override_gid = -1;
799 bool uid_specified = false;
800 bool gid_specified = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000803 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Linus Torvalds12e36b22006-10-13 08:09:29 -0700805 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000806 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000807 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700808 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000809 int n = strnlen(nodename, 15);
810 memset(vol->source_rfc1001_name, 0x20, 15);
811 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000812 /* does not have to be perfect mapping since field is
813 informational, only used for servers that do not support
814 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700815 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 }
818 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700819 /* null target name indicates to use *SMBSERVR default called name
820 if we end up sending RFC1001 session initialize */
821 vol->target_rfc1001_name[0] = 0;
Jeff Layton3e4b3e12010-07-19 18:00:17 -0400822 vol->cred_uid = current_uid();
823 vol->linux_uid = current_uid();
David Howellsa001e5b2008-11-14 10:38:47 +1100824 vol->linux_gid = current_gid();
Jeff Laytonf55ed1a2009-05-26 16:28:11 -0400825
826 /* default to only allowing write access to owner of the mount */
827 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Jeremy Allisonac670552005-06-22 17:26:35 -0700830 /* default is always to request posix paths. */
831 vol->posix_paths = 1;
Jeff Laytona0c92172009-05-27 15:40:47 -0400832 /* default to using server inode numbers where available */
833 vol->server_ino = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -0700834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (!options)
836 return 1;
837
Steve French50c2f752007-07-13 00:33:32 +0000838 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000839 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 separator[0] = options[4];
841 options += 5;
842 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000843 cFYI(1, "Null separator not allowed");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
845 }
Steve French50c2f752007-07-13 00:33:32 +0000846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 while ((data = strsep(&options, separator)) != NULL) {
848 if (!*data)
849 continue;
850 if ((value = strchr(data, '=')) != NULL)
851 *value++ = '\0';
852
Steve French50c2f752007-07-13 00:33:32 +0000853 /* Have to parse this before we parse for "user" */
854 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000856 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 vol->no_xattr = 1;
858 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000859 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 printk(KERN_WARNING
861 "CIFS: invalid or missing username\n");
862 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000863 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000864 /* null user, ie anonymous, authentication */
865 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 if (strnlen(value, 200) < 200) {
868 vol->username = value;
869 } else {
870 printk(KERN_WARNING "CIFS: username too long\n");
871 return 1;
872 }
873 } else if (strnicmp(data, "pass", 4) == 0) {
874 if (!value) {
875 vol->password = NULL;
876 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000877 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* check if string begins with double comma
879 since that would mean the password really
880 does start with a comma, and would not
881 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000882 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 vol->password = NULL;
884 continue;
885 }
886 }
887 temp_len = strlen(value);
888 /* removed password length check, NTLM passwords
889 can be arbitrarily long */
890
Steve French50c2f752007-07-13 00:33:32 +0000891 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 prematurely null terminated. Commas in password are
893 specified across the cifs mount interface by a double
894 comma ie ,, and a comma used as in other cases ie ','
895 as a parameter delimiter/separator is single and due
896 to the strsep above is temporarily zeroed. */
897
898 /* NB: password legally can have multiple commas and
899 the only illegal character in a password is null */
900
Steve French50c2f752007-07-13 00:33:32 +0000901 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700902 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 /* reinsert comma */
904 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000905 temp_len += 2; /* move after second comma */
906 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000908 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700909 separator[0]) {
910 /* skip second comma */
911 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000912 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 /* single comma indicating start
914 of next parm */
915 break;
916 }
917 }
918 temp_len++;
919 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000920 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 options = NULL;
922 } else {
923 value[temp_len] = 0;
924 /* point option to start of next parm */
925 options = value + temp_len + 1;
926 }
Steve French50c2f752007-07-13 00:33:32 +0000927 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 double commas to singles. Note that this ends up
929 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700930 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000931 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000932 printk(KERN_WARNING "CIFS: no memory "
933 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700934 return 1;
935 }
Steve French50c2f752007-07-13 00:33:32 +0000936 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000938 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700939 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* skip second comma */
941 i++;
942 }
943 }
944 vol->password[j] = 0;
945 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700946 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000947 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000948 printk(KERN_WARNING "CIFS: no memory "
949 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700950 return 1;
951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 strcpy(vol->password, value);
953 }
Jeff Layton58f7f682009-06-10 09:57:55 -0400954 } else if (!strnicmp(data, "ip", 2) ||
955 !strnicmp(data, "addr", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 if (!value || !*value) {
957 vol->UNCip = NULL;
Jeff Layton50b64e32009-06-02 06:55:20 -0400958 } else if (strnlen(value, INET6_ADDRSTRLEN) <
959 INET6_ADDRSTRLEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 vol->UNCip = value;
961 } else {
Steve French50c2f752007-07-13 00:33:32 +0000962 printk(KERN_WARNING "CIFS: ip address "
963 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return 1;
965 }
Steve French50c2f752007-07-13 00:33:32 +0000966 } else if (strnicmp(data, "sec", 3) == 0) {
967 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000968 cERROR(1, "no security value specified");
Steve French50c2f752007-07-13 00:33:32 +0000969 continue;
970 } else if (strnicmp(value, "krb5i", 5) == 0) {
971 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000972 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800973 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000974 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
975 CIFSSEC_MAY_KRB5; */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000976 cERROR(1, "Krb5 cifs privacy not supported");
Steve Frenchbf820672005-12-01 22:32:42 -0800977 return 1;
978 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000979 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchac683922009-05-06 04:16:04 +0000980#ifdef CONFIG_CIFS_EXPERIMENTAL
981 } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
982 vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
983 CIFSSEC_MUST_SIGN;
984 } else if (strnicmp(value, "ntlmssp", 7) == 0) {
985 vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
986#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800987 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000988 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000989 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800990 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000991 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800992 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000994 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800995 } else if (strnicmp(value, "ntlm", 4) == 0) {
996 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000997 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800998 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000999 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +00001000 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +00001001#ifdef CONFIG_CIFS_WEAK_PW_HASH
1002 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001003 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001004#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001005 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001006 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001007 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cERROR(1, "bad security option: %s", value);
Steve French50c2f752007-07-13 00:33:32 +00001009 return 1;
1010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 } else if ((strnicmp(data, "unc", 3) == 0)
1012 || (strnicmp(data, "target", 6) == 0)
1013 || (strnicmp(data, "path", 4) == 0)) {
1014 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001015 printk(KERN_WARNING "CIFS: invalid path to "
1016 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return 1; /* needs_arg; */
1018 }
1019 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001020 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001021 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001023 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (strncmp(vol->UNC, "//", 2) == 0) {
1025 vol->UNC[0] = '\\';
1026 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001027 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001029 "CIFS: UNC Path does not begin "
1030 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 1;
1032 }
1033 } else {
1034 printk(KERN_WARNING "CIFS: UNC name too long\n");
1035 return 1;
1036 }
1037 } else if ((strnicmp(data, "domain", 3) == 0)
1038 || (strnicmp(data, "workgroup", 5) == 0)) {
1039 if (!value || !*value) {
1040 printk(KERN_WARNING "CIFS: invalid domain name\n");
1041 return 1; /* needs_arg; */
1042 }
1043 /* BB are there cases in which a comma can be valid in
1044 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001045 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 vol->domainname = value;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001047 cFYI(1, "Domain name set");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 } else {
Steve French50c2f752007-07-13 00:33:32 +00001049 printk(KERN_WARNING "CIFS: domain name too "
1050 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 return 1;
1052 }
Ben Greear3eb9a882010-09-01 17:06:02 -07001053 } else if (strnicmp(data, "srcaddr", 7) == 0) {
1054 vol->srcaddr.ss_family = AF_UNSPEC;
1055
1056 if (!value || !*value) {
1057 printk(KERN_WARNING "CIFS: srcaddr value"
1058 " not specified.\n");
1059 return 1; /* needs_arg; */
1060 }
1061 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
1062 value, strlen(value));
1063 if (i < 0) {
1064 printk(KERN_WARNING "CIFS: Could not parse"
1065 " srcaddr: %s\n",
1066 value);
1067 return 1;
1068 }
Steve French50c2f752007-07-13 00:33:32 +00001069 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1070 if (!value || !*value) {
1071 printk(KERN_WARNING
1072 "CIFS: invalid path prefix\n");
1073 return 1; /* needs_argument */
1074 }
1075 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001076 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001077 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001078 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1079 if (vol->prepath == NULL)
1080 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001081 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001082 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001083 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001084 } else
Steve French50c2f752007-07-13 00:33:32 +00001085 strcpy(vol->prepath, value);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001086 cFYI(1, "prefix path %s", vol->prepath);
Steve French50c2f752007-07-13 00:33:32 +00001087 } else {
1088 printk(KERN_WARNING "CIFS: prefix too long\n");
1089 return 1;
1090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 } else if (strnicmp(data, "iocharset", 9) == 0) {
1092 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001093 printk(KERN_WARNING "CIFS: invalid iocharset "
1094 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return 1; /* needs_arg; */
1096 }
1097 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001098 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001100 /* if iocharset not set then load_nls_default
1101 is used by caller */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001102 cFYI(1, "iocharset set to %s", value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 } else {
Steve French63135e02007-07-17 17:34:02 +00001104 printk(KERN_WARNING "CIFS: iocharset name "
1105 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 return 1;
1107 }
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001108 } else if (!strnicmp(data, "uid", 3) && value && *value) {
1109 vol->linux_uid = simple_strtoul(value, &value, 0);
1110 uid_specified = true;
1111 } else if (!strnicmp(data, "forceuid", 8)) {
1112 override_uid = 1;
1113 } else if (!strnicmp(data, "noforceuid", 10)) {
1114 override_uid = 0;
1115 } else if (!strnicmp(data, "gid", 3) && value && *value) {
1116 vol->linux_gid = simple_strtoul(value, &value, 0);
1117 gid_specified = true;
1118 } else if (!strnicmp(data, "forcegid", 8)) {
1119 override_gid = 1;
1120 } else if (!strnicmp(data, "noforcegid", 10)) {
1121 override_gid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 } else if (strnicmp(data, "file_mode", 4) == 0) {
1123 if (value && *value) {
1124 vol->file_mode =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1128 if (value && *value) {
1129 vol->dir_mode =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "dirmode", 4) == 0) {
1133 if (value && *value) {
1134 vol->dir_mode =
1135 simple_strtoul(value, &value, 0);
1136 }
1137 } else if (strnicmp(data, "port", 4) == 0) {
1138 if (value && *value) {
1139 vol->port =
1140 simple_strtoul(value, &value, 0);
1141 }
1142 } else if (strnicmp(data, "rsize", 5) == 0) {
1143 if (value && *value) {
1144 vol->rsize =
1145 simple_strtoul(value, &value, 0);
1146 }
1147 } else if (strnicmp(data, "wsize", 5) == 0) {
1148 if (value && *value) {
1149 vol->wsize =
1150 simple_strtoul(value, &value, 0);
1151 }
1152 } else if (strnicmp(data, "sockopt", 5) == 0) {
Steve French6a5fa2362010-01-01 01:28:43 +00001153 if (!value || !*value) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001154 cERROR(1, "no socket option specified");
Steve French6a5fa2362010-01-01 01:28:43 +00001155 continue;
1156 } else if (strnicmp(value, "TCP_NODELAY", 11) == 0) {
1157 vol->sockopt_tcp_nodelay = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
1159 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1160 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001161 cFYI(1, "invalid (empty) netbiosname");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 } else {
Steve French50c2f752007-07-13 00:33:32 +00001163 memset(vol->source_rfc1001_name, 0x20, 15);
1164 for (i = 0; i < 15; i++) {
1165 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 valid in this workstation netbios name (and need
1167 special handling)? */
1168
1169 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001170 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 break;
Steve French50c2f752007-07-13 00:33:32 +00001172 else
1173 vol->source_rfc1001_name[i] =
1174 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 }
1176 /* The string has 16th byte zero still from
1177 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001178 if ((i == 15) && (value[i] != 0))
1179 printk(KERN_WARNING "CIFS: netbiosname"
1180 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001181 }
1182 } else if (strnicmp(data, "servern", 7) == 0) {
1183 /* servernetbiosname specified override *SMBSERVER */
1184 if (!value || !*value || (*value == ' ')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001185 cFYI(1, "empty server netbiosname specified");
Steve Frencha10faeb22005-08-22 21:38:31 -07001186 } else {
1187 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001188 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001189
Steve French50c2f752007-07-13 00:33:32 +00001190 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001191 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001192 valid in this workstation netbios name
1193 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001194
Steve French50c2f752007-07-13 00:33:32 +00001195 /* user or mount helper must uppercase
1196 the netbiosname */
1197 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001198 break;
1199 else
Steve French50c2f752007-07-13 00:33:32 +00001200 vol->target_rfc1001_name[i] =
1201 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001202 }
1203 /* The string has 16th byte zero still from
1204 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001205 if ((i == 15) && (value[i] != 0))
1206 printk(KERN_WARNING "CIFS: server net"
1207 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 }
1209 } else if (strnicmp(data, "credentials", 4) == 0) {
1210 /* ignore */
1211 } else if (strnicmp(data, "version", 3) == 0) {
1212 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001213 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 /* ignore */
Steve French71a394f2009-06-26 04:07:18 +00001215 } else if (strnicmp(data, "rw", 2) == 0) {
1216 /* ignore */
1217 } else if (strnicmp(data, "ro", 2) == 0) {
1218 /* ignore */
Steve Frenchedf1ae42008-10-29 00:47:57 +00001219 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1220 vol->noblocksnd = 1;
1221 } else if (strnicmp(data, "noautotune", 10) == 0) {
1222 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 } else if ((strnicmp(data, "suid", 4) == 0) ||
1224 (strnicmp(data, "nosuid", 6) == 0) ||
1225 (strnicmp(data, "exec", 4) == 0) ||
1226 (strnicmp(data, "noexec", 6) == 0) ||
1227 (strnicmp(data, "nodev", 5) == 0) ||
1228 (strnicmp(data, "noauto", 6) == 0) ||
1229 (strnicmp(data, "dev", 3) == 0)) {
1230 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001231 uses these opts to set flags, and the flags are read
1232 by the kernel vfs layer before we get here (ie
1233 before read super) so there is no point trying to
1234 parse these options again and set anything and it
1235 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 } else if (strnicmp(data, "hard", 4) == 0) {
1238 vol->retry = 1;
1239 } else if (strnicmp(data, "soft", 4) == 0) {
1240 vol->retry = 0;
1241 } else if (strnicmp(data, "perm", 4) == 0) {
1242 vol->noperm = 0;
1243 } else if (strnicmp(data, "noperm", 6) == 0) {
1244 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001245 } else if (strnicmp(data, "mapchars", 8) == 0) {
1246 vol->remap = 1;
1247 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1248 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001249 } else if (strnicmp(data, "sfu", 3) == 0) {
1250 vol->sfu_emul = 1;
1251 } else if (strnicmp(data, "nosfu", 5) == 0) {
1252 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001253 } else if (strnicmp(data, "nodfs", 5) == 0) {
1254 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001255 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1256 vol->posix_paths = 1;
1257 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1258 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001259 } else if (strnicmp(data, "nounix", 6) == 0) {
1260 vol->no_linux_ext = 1;
1261 } else if (strnicmp(data, "nolinux", 7) == 0) {
1262 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001263 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001264 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001265 vol->nocase = 1;
Jeff Laytonf636a342010-07-26 10:29:58 -04001266 } else if (strnicmp(data, "mand", 4) == 0) {
1267 /* ignore */
1268 } else if (strnicmp(data, "nomand", 6) == 0) {
1269 /* ignore */
1270 } else if (strnicmp(data, "_netdev", 7) == 0) {
1271 /* ignore */
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001272 } else if (strnicmp(data, "brl", 3) == 0) {
1273 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001274 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001275 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001276 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001277 /* turn off mandatory locking in mode
1278 if remote locking is turned off since the
1279 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001280 if (vol->file_mode ==
1281 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001282 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001283 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1284 /* will take the shorter form "forcemand" as well */
1285 /* This mount option will force use of mandatory
1286 (DOS/Windows style) byte range locks, instead of
1287 using posix advisory byte range locks, even if the
1288 Unix extensions are available and posix locks would
1289 be supported otherwise. If Unix extensions are not
1290 negotiated this has no effect since mandatory locks
1291 would be used (mandatory locks is all that those
1292 those servers support) */
1293 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 } else if (strnicmp(data, "setuids", 7) == 0) {
1295 vol->setuids = 1;
1296 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1297 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001298 } else if (strnicmp(data, "dynperm", 7) == 0) {
1299 vol->dynperm = true;
1300 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1301 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 } else if (strnicmp(data, "nohard", 6) == 0) {
1303 vol->retry = 0;
1304 } else if (strnicmp(data, "nosoft", 6) == 0) {
1305 vol->retry = 1;
1306 } else if (strnicmp(data, "nointr", 6) == 0) {
1307 vol->intr = 0;
1308 } else if (strnicmp(data, "intr", 4) == 0) {
1309 vol->intr = 1;
Steve Frenchbe652442009-02-23 15:21:59 +00001310 } else if (strnicmp(data, "nostrictsync", 12) == 0) {
1311 vol->nostrictsync = 1;
1312 } else if (strnicmp(data, "strictsync", 10) == 0) {
1313 vol->nostrictsync = 0;
Steve French50c2f752007-07-13 00:33:32 +00001314 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001316 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001318 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001319 vol->cifs_acl = 1;
1320 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1321 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001322 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001324 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001326#ifdef CONFIG_CIFS_EXPERIMENTAL
1327 } else if (strnicmp(data, "locallease", 6) == 0) {
1328 vol->local_lease = 1;
1329#endif
Steve French50c2f752007-07-13 00:33:32 +00001330 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001331 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001332 } else if (strnicmp(data, "seal", 4) == 0) {
1333 /* we do not do the following in secFlags because seal
1334 is a per tree connection (mount) not a per socket
1335 or per-smb connection option in the protocol */
1336 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1337 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001338 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001340 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 vol->direct_io = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001343 printk(KERN_WARNING "CIFS: Mount option noac not "
1344 "supported. Instead set "
1345 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05301346 } else if (strnicmp(data, "fsc", 3) == 0) {
1347 vol->fsc = true;
Stefan Metzmacher736a3322010-07-30 14:56:00 +02001348 } else if (strnicmp(data, "mfsymlinks", 10) == 0) {
1349 vol->mfsymlinks = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 } else
Steve French50c2f752007-07-13 00:33:32 +00001351 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1352 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 }
1354 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001355 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001356 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1357 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 return 1;
1359 }
1360 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001361 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001362 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001364 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (strncmp(vol->UNC, "//", 2) == 0) {
1366 vol->UNC[0] = '\\';
1367 vol->UNC[1] = '\\';
1368 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001369 printk(KERN_WARNING "CIFS: UNC Path does not "
1370 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return 1;
1372 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001373 value = strpbrk(vol->UNC+2, "/\\");
1374 if (value)
1375 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 } else {
1377 printk(KERN_WARNING "CIFS: UNC name too long\n");
1378 return 1;
1379 }
1380 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001381 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 vol->UNCip = &vol->UNC[2];
1383
Jeff Layton9b9d6b242009-07-31 06:56:09 -04001384 if (uid_specified)
1385 vol->override_uid = override_uid;
1386 else if (override_uid == 1)
1387 printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
1388 "specified with no uid= option.\n");
1389
1390 if (gid_specified)
1391 vol->override_gid = override_gid;
1392 else if (override_gid == 1)
1393 printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
1394 "specified with no gid= option.\n");
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 return 0;
1397}
1398
Ben Greear3eb9a882010-09-01 17:06:02 -07001399/** Returns true if srcaddr isn't specified and rhs isn't
1400 * specified, or if srcaddr is specified and
1401 * matches the IP address of the rhs argument.
1402 */
Jeff Layton45151482010-07-06 20:43:02 -04001403static bool
Ben Greear3eb9a882010-09-01 17:06:02 -07001404srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
1405{
1406 switch (srcaddr->sa_family) {
1407 case AF_UNSPEC:
1408 return (rhs->sa_family == AF_UNSPEC);
1409 case AF_INET: {
1410 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1411 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1412 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1413 }
1414 case AF_INET6: {
1415 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1416 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
1417 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1418 }
1419 default:
1420 WARN_ON(1);
1421 return false; /* don't expect to be here */
1422 }
1423}
1424
1425
1426static bool
1427match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1428 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
Jeff Layton45151482010-07-06 20:43:02 -04001430 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1431 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1432
1433 switch (addr->sa_family) {
1434 case AF_INET:
1435 if (addr4->sin_addr.s_addr !=
1436 server->addr.sockAddr.sin_addr.s_addr)
1437 return false;
1438 if (addr4->sin_port &&
1439 addr4->sin_port != server->addr.sockAddr.sin_port)
1440 return false;
1441 break;
1442 case AF_INET6:
1443 if (!ipv6_addr_equal(&addr6->sin6_addr,
1444 &server->addr.sockAddr6.sin6_addr))
1445 return false;
1446 if (addr6->sin6_scope_id !=
1447 server->addr.sockAddr6.sin6_scope_id)
1448 return false;
1449 if (addr6->sin6_port &&
1450 addr6->sin6_port != server->addr.sockAddr6.sin6_port)
1451 return false;
1452 break;
1453 }
1454
Ben Greear3eb9a882010-09-01 17:06:02 -07001455 if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
1456 return false;
1457
Jeff Layton45151482010-07-06 20:43:02 -04001458 return true;
1459}
1460
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001461static bool
1462match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
1463{
1464 unsigned int secFlags;
1465
1466 if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
1467 secFlags = vol->secFlg;
1468 else
1469 secFlags = global_secflags | vol->secFlg;
1470
1471 switch (server->secType) {
1472 case LANMAN:
1473 if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
1474 return false;
1475 break;
1476 case NTLMv2:
1477 if (!(secFlags & CIFSSEC_MAY_NTLMV2))
1478 return false;
1479 break;
1480 case NTLM:
1481 if (!(secFlags & CIFSSEC_MAY_NTLM))
1482 return false;
1483 break;
1484 case Kerberos:
1485 if (!(secFlags & CIFSSEC_MAY_KRB5))
1486 return false;
1487 break;
1488 case RawNTLMSSP:
1489 if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
1490 return false;
1491 break;
1492 default:
1493 /* shouldn't happen */
1494 return false;
1495 }
1496
1497 /* now check if signing mode is acceptible */
1498 if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
1499 (server->secMode & SECMODE_SIGN_REQUIRED))
1500 return false;
1501 else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
1502 (server->secMode &
1503 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
1504 return false;
1505
1506 return true;
1507}
1508
Jeff Layton45151482010-07-06 20:43:02 -04001509static struct TCP_Server_Info *
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001510cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
Jeff Layton45151482010-07-06 20:43:02 -04001511{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001512 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
Jeff Laytone7ddee92008-11-14 13:44:38 -05001514 write_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001515 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Ben Greear3eb9a882010-09-01 17:06:02 -07001516 if (!match_address(server, addr,
1517 (struct sockaddr *)&vol->srcaddr))
Jeff Layton45151482010-07-06 20:43:02 -04001518 continue;
Steve French50c2f752007-07-13 00:33:32 +00001519
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001520 if (!match_security(server, vol))
1521 continue;
1522
Jeff Laytone7ddee92008-11-14 13:44:38 -05001523 ++server->srv_count;
1524 write_unlock(&cifs_tcp_ses_lock);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001525 cFYI(1, "Existing tcp session with server found");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001526 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001528 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 return NULL;
1530}
1531
Jeff Layton14fbf502008-11-14 13:53:46 -05001532static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001533cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001535 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
Jeff Laytone7ddee92008-11-14 13:44:38 -05001537 write_lock(&cifs_tcp_ses_lock);
1538 if (--server->srv_count > 0) {
1539 write_unlock(&cifs_tcp_ses_lock);
1540 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 }
Steve Frenchdea570e2008-05-06 22:05:51 +00001542
Jeff Laytone7ddee92008-11-14 13:44:38 -05001543 list_del_init(&server->tcp_ses_list);
1544 write_unlock(&cifs_tcp_ses_lock);
1545
1546 spin_lock(&GlobalMid_Lock);
1547 server->tcpStatus = CifsExiting;
1548 spin_unlock(&GlobalMid_Lock);
1549
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301550 cifs_fscache_release_client_cookie(server);
1551
Jeff Laytone7ddee92008-11-14 13:44:38 -05001552 task = xchg(&server->tsk, NULL);
1553 if (task)
1554 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555}
1556
Jeff Layton63c038c2008-12-01 18:41:46 -05001557static struct TCP_Server_Info *
1558cifs_get_tcp_session(struct smb_vol *volume_info)
1559{
1560 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001561 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05001562 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1563 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1564 int rc;
1565
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001566 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05001567
Joe Perchesb6b38f72010-04-21 03:50:45 +00001568 cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001569
Jeff Layton63c038c2008-12-01 18:41:46 -05001570 if (volume_info->UNCip && volume_info->UNC) {
Jeff Layton50d97162010-07-06 20:43:01 -04001571 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
1572 volume_info->UNCip,
David Howells67b76262010-07-22 18:33:01 +01001573 strlen(volume_info->UNCip),
Jeff Layton50d97162010-07-06 20:43:01 -04001574 volume_info->port);
Jeff Layton1e68b2b2009-06-11 10:27:30 -04001575 if (!rc) {
Jeff Layton63c038c2008-12-01 18:41:46 -05001576 /* we failed translating address */
1577 rc = -EINVAL;
1578 goto out_err;
1579 }
Jeff Layton63c038c2008-12-01 18:41:46 -05001580 } else if (volume_info->UNCip) {
1581 /* BB using ip addr as tcp_ses name to connect to the
1582 DFS root below */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001583 cERROR(1, "Connecting to DFS root not implemented yet");
Jeff Layton63c038c2008-12-01 18:41:46 -05001584 rc = -EINVAL;
1585 goto out_err;
1586 } else /* which tcp_sess DFS root would we conect to */ {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001587 cERROR(1, "CIFS mount error: No UNC path (e.g. -o "
1588 "unc=//192.168.1.100/public) specified");
Jeff Layton63c038c2008-12-01 18:41:46 -05001589 rc = -EINVAL;
1590 goto out_err;
1591 }
1592
1593 /* see if we already have a matching tcp_ses */
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001594 tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05001595 if (tcp_ses)
1596 return tcp_ses;
1597
1598 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1599 if (!tcp_ses) {
1600 rc = -ENOMEM;
1601 goto out_err;
1602 }
1603
1604 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1605 if (IS_ERR(tcp_ses->hostname)) {
1606 rc = PTR_ERR(tcp_ses->hostname);
1607 goto out_err;
1608 }
1609
1610 tcp_ses->noblocksnd = volume_info->noblocksnd;
1611 tcp_ses->noautotune = volume_info->noautotune;
Steve French6a5fa2362010-01-01 01:28:43 +00001612 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
Jeff Layton63c038c2008-12-01 18:41:46 -05001613 atomic_set(&tcp_ses->inFlight, 0);
1614 init_waitqueue_head(&tcp_ses->response_q);
1615 init_waitqueue_head(&tcp_ses->request_q);
1616 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1617 mutex_init(&tcp_ses->srv_mutex);
1618 memcpy(tcp_ses->workstation_RFC1001_name,
1619 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1620 memcpy(tcp_ses->server_RFC1001_name,
1621 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1622 tcp_ses->sequence_number = 0;
1623 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1624 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1625
1626 /*
1627 * at this point we are the only ones with the pointer
1628 * to the struct since the kernel thread not created yet
1629 * no need to spinlock this init of tcpStatus or srv_count
1630 */
1631 tcp_ses->tcpStatus = CifsNew;
Ben Greear3eb9a882010-09-01 17:06:02 -07001632 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
1633 sizeof(tcp_ses->srcaddr));
Jeff Layton63c038c2008-12-01 18:41:46 -05001634 ++tcp_ses->srv_count;
1635
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001636 if (addr.ss_family == AF_INET6) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001637 cFYI(1, "attempting ipv6 connect");
Jeff Layton63c038c2008-12-01 18:41:46 -05001638 /* BB should we allow ipv6 on port 139? */
1639 /* other OS never observed in Wild doing 139 with v6 */
1640 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1641 sizeof(struct sockaddr_in6));
Jeff Laytond5c56052008-12-01 18:42:33 -05001642 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001643 } else {
1644 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1645 sizeof(struct sockaddr_in));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001646 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001647 }
1648 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001649 cERROR(1, "Error connecting to socket. Aborting operation");
Jeff Layton63c038c2008-12-01 18:41:46 -05001650 goto out_err;
1651 }
1652
1653 /*
1654 * since we're in a cifs function already, we know that
1655 * this will succeed. No need for try_module_get().
1656 */
1657 __module_get(THIS_MODULE);
1658 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1659 tcp_ses, "cifsd");
1660 if (IS_ERR(tcp_ses->tsk)) {
1661 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001662 cERROR(1, "error %d create cifsd thread", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05001663 module_put(THIS_MODULE);
1664 goto out_err;
1665 }
1666
1667 /* thread spawned, put it on the list */
1668 write_lock(&cifs_tcp_ses_lock);
1669 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1670 write_unlock(&cifs_tcp_ses_lock);
1671
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301672 cifs_fscache_get_client_cookie(tcp_ses);
1673
Jeff Layton63c038c2008-12-01 18:41:46 -05001674 return tcp_ses;
1675
1676out_err:
1677 if (tcp_ses) {
Steve French8347a5cd2009-10-06 18:31:29 +00001678 if (!IS_ERR(tcp_ses->hostname))
1679 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05001680 if (tcp_ses->ssocket)
1681 sock_release(tcp_ses->ssocket);
1682 kfree(tcp_ses);
1683 }
1684 return ERR_PTR(rc);
1685}
1686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687static struct cifsSesInfo *
Jeff Layton4ff67b72010-07-06 20:43:02 -04001688cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 struct cifsSesInfo *ses;
1691
Jeff Layton14fbf502008-11-14 13:53:46 -05001692 write_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04001693 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1694 switch (server->secType) {
1695 case Kerberos:
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001696 if (vol->cred_uid != ses->cred_uid)
Jeff Layton4ff67b72010-07-06 20:43:02 -04001697 continue;
1698 break;
1699 default:
1700 /* anything else takes username/password */
1701 if (strncmp(ses->userName, vol->username,
1702 MAX_USERNAME_SIZE))
1703 continue;
1704 if (strlen(vol->username) != 0 &&
Jeff Layton24e6cf92010-08-23 11:38:04 -04001705 ses->password != NULL &&
Jeff Laytonfc87a402010-08-18 13:13:39 -04001706 strncmp(ses->password,
1707 vol->password ? vol->password : "",
Jeff Layton4ff67b72010-07-06 20:43:02 -04001708 MAX_PASSWORD_SIZE))
1709 continue;
1710 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001711 ++ses->ses_count;
1712 write_unlock(&cifs_tcp_ses_lock);
1713 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001715 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return NULL;
1717}
1718
Jeff Layton14fbf502008-11-14 13:53:46 -05001719static void
1720cifs_put_smb_ses(struct cifsSesInfo *ses)
1721{
1722 int xid;
1723 struct TCP_Server_Info *server = ses->server;
1724
Jeff Layton36988c72010-04-24 07:57:43 -04001725 cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count);
Jeff Layton14fbf502008-11-14 13:53:46 -05001726 write_lock(&cifs_tcp_ses_lock);
1727 if (--ses->ses_count > 0) {
1728 write_unlock(&cifs_tcp_ses_lock);
1729 return;
1730 }
1731
1732 list_del_init(&ses->smb_ses_list);
1733 write_unlock(&cifs_tcp_ses_lock);
1734
1735 if (ses->status == CifsGood) {
1736 xid = GetXid();
1737 CIFSSMBLogoff(xid, ses);
1738 _FreeXid(xid);
1739 }
1740 sesInfoFree(ses);
1741 cifs_put_tcp_session(server);
1742}
1743
Jeff Layton36988c72010-04-24 07:57:43 -04001744static struct cifsSesInfo *
1745cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1746{
1747 int rc = -ENOMEM, xid;
1748 struct cifsSesInfo *ses;
1749
1750 xid = GetXid();
1751
Jeff Layton4ff67b72010-07-06 20:43:02 -04001752 ses = cifs_find_smb_ses(server, volume_info);
Jeff Layton36988c72010-04-24 07:57:43 -04001753 if (ses) {
1754 cFYI(1, "Existing smb sess found (status=%d)", ses->status);
1755
Jeff Layton36988c72010-04-24 07:57:43 -04001756 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001757 rc = cifs_negotiate_protocol(xid, ses);
1758 if (rc) {
1759 mutex_unlock(&ses->session_mutex);
1760 /* problem -- put our ses reference */
1761 cifs_put_smb_ses(ses);
1762 FreeXid(xid);
1763 return ERR_PTR(rc);
1764 }
Jeff Layton36988c72010-04-24 07:57:43 -04001765 if (ses->need_reconnect) {
1766 cFYI(1, "Session needs reconnect");
1767 rc = cifs_setup_session(xid, ses,
1768 volume_info->local_nls);
1769 if (rc) {
1770 mutex_unlock(&ses->session_mutex);
1771 /* problem -- put our reference */
1772 cifs_put_smb_ses(ses);
1773 FreeXid(xid);
1774 return ERR_PTR(rc);
1775 }
1776 }
1777 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04001778
1779 /* existing SMB ses has a server reference already */
1780 cifs_put_tcp_session(server);
Jeff Layton36988c72010-04-24 07:57:43 -04001781 FreeXid(xid);
1782 return ses;
1783 }
1784
1785 cFYI(1, "Existing smb sess not found");
1786 ses = sesInfoAlloc();
1787 if (ses == NULL)
1788 goto get_ses_fail;
1789
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -05001790 ses->tilen = 0;
1791 ses->tiblob = NULL;
Jeff Layton36988c72010-04-24 07:57:43 -04001792 /* new SMB session uses our server ref */
1793 ses->server = server;
1794 if (server->addr.sockAddr6.sin6_family == AF_INET6)
1795 sprintf(ses->serverName, "%pI6",
1796 &server->addr.sockAddr6.sin6_addr);
1797 else
1798 sprintf(ses->serverName, "%pI4",
1799 &server->addr.sockAddr.sin_addr.s_addr);
1800
1801 if (volume_info->username)
1802 strncpy(ses->userName, volume_info->username,
1803 MAX_USERNAME_SIZE);
1804
1805 /* volume_info->password freed at unmount */
1806 if (volume_info->password) {
1807 ses->password = kstrdup(volume_info->password, GFP_KERNEL);
1808 if (!ses->password)
1809 goto get_ses_fail;
1810 }
1811 if (volume_info->domainname) {
1812 int len = strlen(volume_info->domainname);
1813 ses->domainName = kmalloc(len + 1, GFP_KERNEL);
1814 if (ses->domainName)
1815 strcpy(ses->domainName, volume_info->domainname);
1816 }
Jeff Layton3e4b3e12010-07-19 18:00:17 -04001817 ses->cred_uid = volume_info->cred_uid;
Jeff Layton36988c72010-04-24 07:57:43 -04001818 ses->linux_uid = volume_info->linux_uid;
1819 ses->overrideSecFlg = volume_info->secFlg;
1820
1821 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001822 rc = cifs_negotiate_protocol(xid, ses);
1823 if (!rc)
1824 rc = cifs_setup_session(xid, ses, volume_info->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04001825 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00001826 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04001827 goto get_ses_fail;
1828
1829 /* success, put it on the list */
1830 write_lock(&cifs_tcp_ses_lock);
1831 list_add(&ses->smb_ses_list, &server->smb_ses_list);
1832 write_unlock(&cifs_tcp_ses_lock);
1833
1834 FreeXid(xid);
1835 return ses;
1836
1837get_ses_fail:
1838 sesInfoFree(ses);
1839 FreeXid(xid);
1840 return ERR_PTR(rc);
1841}
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001844cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845{
1846 struct list_head *tmp;
1847 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Jeff Laytonf1987b42008-11-15 11:12:47 -05001849 write_lock(&cifs_tcp_ses_lock);
1850 list_for_each(tmp, &ses->tcon_list) {
1851 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1852 if (tcon->tidStatus == CifsExiting)
1853 continue;
1854 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 continue;
1856
Jeff Laytonf1987b42008-11-15 11:12:47 -05001857 ++tcon->tc_count;
1858 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 return tcon;
1860 }
Jeff Laytonf1987b42008-11-15 11:12:47 -05001861 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 return NULL;
1863}
1864
Jeff Laytonf1987b42008-11-15 11:12:47 -05001865static void
1866cifs_put_tcon(struct cifsTconInfo *tcon)
1867{
1868 int xid;
1869 struct cifsSesInfo *ses = tcon->ses;
1870
Jeff Laytond00c28d2010-04-24 07:57:44 -04001871 cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001872 write_lock(&cifs_tcp_ses_lock);
1873 if (--tcon->tc_count > 0) {
1874 write_unlock(&cifs_tcp_ses_lock);
1875 return;
1876 }
1877
1878 list_del_init(&tcon->tcon_list);
1879 write_unlock(&cifs_tcp_ses_lock);
1880
1881 xid = GetXid();
1882 CIFSSMBTDis(xid, tcon);
1883 _FreeXid(xid);
1884
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301885 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00001886 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001887 cifs_put_smb_ses(ses);
1888}
1889
Jeff Laytond00c28d2010-04-24 07:57:44 -04001890static struct cifsTconInfo *
1891cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
1892{
1893 int rc, xid;
1894 struct cifsTconInfo *tcon;
1895
1896 tcon = cifs_find_tcon(ses, volume_info->UNC);
1897 if (tcon) {
1898 cFYI(1, "Found match on UNC path");
1899 /* existing tcon already has a reference */
1900 cifs_put_smb_ses(ses);
1901 if (tcon->seal != volume_info->seal)
1902 cERROR(1, "transport encryption setting "
1903 "conflicts with existing tid");
1904 return tcon;
1905 }
1906
1907 tcon = tconInfoAlloc();
1908 if (tcon == NULL) {
1909 rc = -ENOMEM;
1910 goto out_fail;
1911 }
1912
1913 tcon->ses = ses;
1914 if (volume_info->password) {
1915 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
1916 if (!tcon->password) {
1917 rc = -ENOMEM;
1918 goto out_fail;
1919 }
1920 }
1921
1922 if (strchr(volume_info->UNC + 3, '\\') == NULL
1923 && strchr(volume_info->UNC + 3, '/') == NULL) {
1924 cERROR(1, "Missing share name");
1925 rc = -ENODEV;
1926 goto out_fail;
1927 }
1928
1929 /* BB Do we need to wrap session_mutex around
1930 * this TCon call and Unix SetFS as
1931 * we do on SessSetup and reconnect? */
1932 xid = GetXid();
1933 rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls);
1934 FreeXid(xid);
1935 cFYI(1, "CIFS Tcon rc = %d", rc);
1936 if (rc)
1937 goto out_fail;
1938
1939 if (volume_info->nodfs) {
1940 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
1941 cFYI(1, "DFS disabled (%d)", tcon->Flags);
1942 }
1943 tcon->seal = volume_info->seal;
1944 /* we can have only one retry value for a connection
1945 to a share so for resources mounted more than once
1946 to the same server share the last value passed in
1947 for the retry flag is used */
1948 tcon->retry = volume_info->retry;
1949 tcon->nocase = volume_info->nocase;
1950 tcon->local_lease = volume_info->local_lease;
1951
1952 write_lock(&cifs_tcp_ses_lock);
1953 list_add(&tcon->tcon_list, &ses->tcon_list);
1954 write_unlock(&cifs_tcp_ses_lock);
1955
Suresh Jayaramand03382c2010-07-05 18:12:27 +05301956 cifs_fscache_get_super_cookie(tcon);
1957
Jeff Laytond00c28d2010-04-24 07:57:44 -04001958 return tcon;
1959
1960out_fail:
1961 tconInfoFree(tcon);
1962 return ERR_PTR(rc);
1963}
1964
Jeff Layton9d002df2010-10-06 19:51:11 -04001965void
1966cifs_put_tlink(struct tcon_link *tlink)
1967{
1968 if (!tlink || IS_ERR(tlink))
1969 return;
1970
1971 if (!atomic_dec_and_test(&tlink->tl_count) ||
1972 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
1973 tlink->tl_time = jiffies;
1974 return;
1975 }
1976
1977 if (!IS_ERR(tlink_tcon(tlink)))
1978 cifs_put_tcon(tlink_tcon(tlink));
1979 kfree(tlink);
1980 return;
1981}
Jeff Laytond00c28d2010-04-24 07:57:44 -04001982
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983int
Steve French50c2f752007-07-13 00:33:32 +00001984get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1985 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001986 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987{
1988 char *temp_unc;
1989 int rc = 0;
1990
1991 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001992 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 if (pSesInfo->ipc_tid == 0) {
1995 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001996 strnlen(pSesInfo->serverName,
1997 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 + 1 + 4 /* slash IPC$ */ + 2,
1999 GFP_KERNEL);
2000 if (temp_unc == NULL)
2001 return -ENOMEM;
2002 temp_unc[0] = '\\';
2003 temp_unc[1] = '\\';
2004 strcpy(temp_unc + 2, pSesInfo->serverName);
2005 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
2006 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002007 cFYI(1, "CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 kfree(temp_unc);
2009 }
2010 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00002011 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07002012 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00002013 /* BB map targetUNCs to dfs_info3 structures, here or
2014 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
2016 return rc;
2017}
2018
Jeff Layton09e50d52008-07-23 10:11:19 -04002019#ifdef CONFIG_DEBUG_LOCK_ALLOC
2020static struct lock_class_key cifs_key[2];
2021static struct lock_class_key cifs_slock_key[2];
2022
2023static inline void
2024cifs_reclassify_socket4(struct socket *sock)
2025{
2026 struct sock *sk = sock->sk;
2027 BUG_ON(sock_owned_by_user(sk));
2028 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2029 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2030}
2031
2032static inline void
2033cifs_reclassify_socket6(struct socket *sock)
2034{
2035 struct sock *sk = sock->sk;
2036 BUG_ON(sock_owned_by_user(sk));
2037 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2038 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2039}
2040#else
2041static inline void
2042cifs_reclassify_socket4(struct socket *sock)
2043{
2044}
2045
2046static inline void
2047cifs_reclassify_socket6(struct socket *sock)
2048{
2049}
2050#endif
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002053static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054{
Steve French50c2f752007-07-13 00:33:32 +00002055 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Steve French50c2f752007-07-13 00:33:32 +00002057 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 /* mask a nibble at a time and encode */
2059 target[j] = 'A' + (0x0F & (source[i] >> 4));
2060 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002061 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 }
2063
2064}
2065
Ben Greear3eb9a882010-09-01 17:06:02 -07002066static int
2067bind_socket(struct TCP_Server_Info *server)
2068{
2069 int rc = 0;
2070 if (server->srcaddr.ss_family != AF_UNSPEC) {
2071 /* Bind to the specified local IP address */
2072 struct socket *socket = server->ssocket;
2073 rc = socket->ops->bind(socket,
2074 (struct sockaddr *) &server->srcaddr,
2075 sizeof(server->srcaddr));
2076 if (rc < 0) {
2077 struct sockaddr_in *saddr4;
2078 struct sockaddr_in6 *saddr6;
2079 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2080 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2081 if (saddr6->sin6_family == AF_INET6)
2082 cERROR(1, "cifs: "
2083 "Failed to bind to: %pI6c, error: %d\n",
2084 &saddr6->sin6_addr, rc);
2085 else
2086 cERROR(1, "cifs: "
2087 "Failed to bind to: %pI4, error: %d\n",
2088 &saddr4->sin_addr.s_addr, rc);
2089 }
2090 }
2091 return rc;
2092}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002095ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096{
2097 int rc = 0;
Steve French6a5fa2362010-01-01 01:28:43 +00002098 int val;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002099 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002101 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002103 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002104 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002105 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002107 cERROR(1, "Error %d creating socket", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002110
2111 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002112 cFYI(1, "Socket created");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002113 server->ssocket = socket;
2114 socket->sk->sk_allocation = GFP_NOFS;
2115 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 }
2117
Ben Greear3eb9a882010-09-01 17:06:02 -07002118 rc = bind_socket(server);
2119 if (rc < 0)
2120 return rc;
2121
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002122 /* user overrode default port */
2123 if (server->addr.sockAddr.sin_port) {
2124 rc = socket->ops->connect(socket, (struct sockaddr *)
2125 &server->addr.sockAddr,
2126 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002128 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00002129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002131 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00002132 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002134 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002137 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
2138 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
2139 rc = socket->ops->connect(socket,
2140 (struct sockaddr *)
2141 &server->addr.sockAddr,
2142 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002144 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 }
2146 }
2147 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002148 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
2149 rc = socket->ops->connect(socket, (struct sockaddr *)
2150 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002151 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00002152 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002153 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 }
2155
2156 /* give up here - unless we want to retry on different
2157 protocol families some day */
2158 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002159 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002160 server->addr.sockAddr.sin_port = orig_port;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002161 cFYI(1, "Error %d connecting to server via ipv4", rc);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002162 sock_release(socket);
2163 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 return rc;
2165 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002166
2167
2168 /*
2169 * Eventually check for other socket options to change from
2170 * the default. sock_setsockopt not used because it expects
2171 * user space buffer
2172 */
2173 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002174 socket->sk->sk_sndtimeo = 5 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00002175
Steve Frenchb387eae2005-10-10 14:21:15 -07002176 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002177 if (server->noautotune) {
2178 if (socket->sk->sk_sndbuf < (200 * 1024))
2179 socket->sk->sk_sndbuf = 200 * 1024;
2180 if (socket->sk->sk_rcvbuf < (140 * 1024))
2181 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00002182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Steve French6a5fa2362010-01-01 01:28:43 +00002184 if (server->tcp_nodelay) {
2185 val = 1;
2186 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
2187 (char *)&val, sizeof(val));
2188 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002189 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00002190 }
2191
Joe Perchesb6b38f72010-04-21 03:50:45 +00002192 cFYI(1, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002193 socket->sk->sk_sndbuf,
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002195
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002197 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00002199 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00002201 struct rfc1002_session_packet *ses_init_buf;
2202 struct smb_hdr *smb_buf;
2203 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2204 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002205 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002207 if (server->server_RFC1001_name &&
2208 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002209 rfc1002mangle(ses_init_buf->trailer.
2210 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002211 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05002212 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002213 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05002214 rfc1002mangle(ses_init_buf->trailer.
2215 session_req.called_name,
2216 DEFAULT_CIFS_CALLED_NAME,
2217 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07002218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002220
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 /* calling name ends in null (byte 16) from old smb
2222 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002223 if (server->workstation_RFC1001_name &&
2224 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002225 rfc1002mangle(ses_init_buf->trailer.
2226 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002227 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05002228 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002229 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05002230 rfc1002mangle(ses_init_buf->trailer.
2231 session_req.calling_name,
2232 "LINUX_CIFS_CLNT",
2233 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 ses_init_buf->trailer.session_req.scope1 = 0;
2236 ses_init_buf->trailer.session_req.scope2 = 0;
2237 smb_buf = (struct smb_hdr *)ses_init_buf;
2238 /* sizeof RFC1002_SESSION_REQUEST with no scope */
2239 smb_buf->smb_buf_length = 0x81000044;
Jeff Layton0496e022008-12-30 12:39:16 -05002240 rc = smb_send(server, smb_buf, 0x44);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00002242 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00002243 requires very short break before negprot
2244 presumably because not expecting negprot
2245 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00002246 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00002247 complicating the code and causes no
2248 significant slowing down on mount
2249 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
Steve French50c2f752007-07-13 00:33:32 +00002251 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00002253
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
Steve French50c2f752007-07-13 00:33:32 +00002255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 return rc;
2257}
2258
2259static int
Jeff Laytond5c56052008-12-01 18:42:33 -05002260ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261{
2262 int rc = 0;
Steve French6a5fa2362010-01-01 01:28:43 +00002263 int val;
Jeff Laytond5c56052008-12-01 18:42:33 -05002264 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05002266 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Jeff Laytond5c56052008-12-01 18:42:33 -05002268 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002269 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05002270 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (rc < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002272 cERROR(1, "Error %d creating ipv6 socket", rc);
Jeff Laytond5c56052008-12-01 18:42:33 -05002273 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Jeff Laytond5c56052008-12-01 18:42:33 -05002276
2277 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002278 cFYI(1, "ipv6 Socket created");
Jeff Laytond5c56052008-12-01 18:42:33 -05002279 server->ssocket = socket;
2280 socket->sk->sk_allocation = GFP_NOFS;
2281 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 }
2283
Ben Greear3eb9a882010-09-01 17:06:02 -07002284 rc = bind_socket(server);
2285 if (rc < 0)
2286 return rc;
2287
Jeff Laytond5c56052008-12-01 18:42:33 -05002288 /* user overrode default port */
2289 if (server->addr.sockAddr6.sin6_port) {
2290 rc = socket->ops->connect(socket,
2291 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002292 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002294 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00002295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002297 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00002298 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 later if fall back ports fail this time */
2300
Jeff Laytond5c56052008-12-01 18:42:33 -05002301 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05002303 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
2304 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
2305 rc = socket->ops->connect(socket, (struct sockaddr *)
2306 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002307 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002309 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 }
2311 }
2312 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05002313 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
2314 rc = socket->ops->connect(socket, (struct sockaddr *)
2315 &server->addr.sockAddr6,
2316 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00002317 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05002318 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 }
2320
2321 /* give up here - unless we want to retry on different
2322 protocol families some day */
2323 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002324 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05002325 server->addr.sockAddr6.sin6_port = orig_port;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002326 cFYI(1, "Error %d connecting to server via ipv6", rc);
Jeff Laytond5c56052008-12-01 18:42:33 -05002327 sock_release(socket);
2328 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 return rc;
2330 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00002331
Jeff Laytond5c56052008-12-01 18:42:33 -05002332 /*
2333 * Eventually check for other socket options to change from
2334 * the default. sock_setsockopt not used because it expects
2335 * user space buffer
2336 */
2337 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002338 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002339
2340 if (server->tcp_nodelay) {
2341 val = 1;
2342 rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY,
2343 (char *)&val, sizeof(val));
2344 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002345 cFYI(1, "set TCP_NODELAY socket option error %d", rc);
Steve French6a5fa2362010-01-01 01:28:43 +00002346 }
2347
Jeff Laytond5c56052008-12-01 18:42:33 -05002348 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00002349
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 return rc;
2351}
2352
Steve French50c2f752007-07-13 00:33:32 +00002353void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
2354 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00002355{
2356 /* if we are reconnecting then should we check to see if
2357 * any requested capabilities changed locally e.g. via
2358 * remount but we can not do much about it here
2359 * if they have (even if we could detect it by the following)
2360 * Perhaps we could add a backpointer to array of sb from tcon
2361 * or if we change to make all sb to same share the same
2362 * sb as NFS - then we only have one backpointer to sb.
2363 * What if we wanted to mount the server share twice once with
2364 * and once without posixacls or posix paths? */
2365 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002366
Steve Frenchc18c8422007-07-18 23:21:09 +00002367 if (vol_info && vol_info->no_linux_ext) {
2368 tcon->fsUnixInfo.Capability = 0;
2369 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002370 cFYI(1, "Linux protocol extensions disabled");
Steve Frenchc18c8422007-07-18 23:21:09 +00002371 return;
2372 } else if (vol_info)
2373 tcon->unix_ext = 1; /* Unix Extensions supported */
2374
2375 if (tcon->unix_ext == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002376 cFYI(1, "Unix extensions disabled so not set on reconnect");
Steve Frenchc18c8422007-07-18 23:21:09 +00002377 return;
2378 }
Steve French50c2f752007-07-13 00:33:32 +00002379
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002380 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002381 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002382
Steve French8af18972007-02-14 04:42:51 +00002383 /* check for reconnect case in which we do not
2384 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002385 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002386 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00002387 originally at mount time */
2388 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2389 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002390 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2391 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002392 cERROR(1, "POSIXPATH support change");
Steve French8af18972007-02-14 04:42:51 +00002393 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002394 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002395 cERROR(1, "possible reconnect error");
2396 cERROR(1, "server disabled POSIX path support");
Igor Mammedov11b6d642008-02-15 19:06:04 +00002397 }
Steve French8af18972007-02-14 04:42:51 +00002398 }
Steve French50c2f752007-07-13 00:33:32 +00002399
Steve French8af18972007-02-14 04:42:51 +00002400 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f82007-06-24 18:30:48 +00002401 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002402 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f82007-06-24 18:30:48 +00002403 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002404 cFYI(1, "negotiated posix acl support");
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002405 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002406 sb->s_flags |= MS_POSIXACL;
2407 }
2408
Steve French75865f82007-06-24 18:30:48 +00002409 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002410 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f82007-06-24 18:30:48 +00002411 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002412 cFYI(1, "negotiate posix pathnames");
Steve French75865f82007-06-24 18:30:48 +00002413 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002414 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002415 CIFS_MOUNT_POSIX_PATHS;
2416 }
Steve French50c2f752007-07-13 00:33:32 +00002417
Steve French984acfe2007-04-26 16:42:50 +00002418 /* We might be setting the path sep back to a different
2419 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002420 posix path capability for this share */
Steve French75865f82007-06-24 18:30:48 +00002421 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002422 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f82007-06-24 18:30:48 +00002423
2424 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2425 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2426 CIFS_SB(sb)->rsize = 127 * 1024;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002427 cFYI(DBG2, "larger reads not supported by srv");
Steve French75865f82007-06-24 18:30:48 +00002428 }
2429 }
Steve French50c2f752007-07-13 00:33:32 +00002430
2431
Joe Perchesb6b38f72010-04-21 03:50:45 +00002432 cFYI(1, "Negotiate caps 0x%x", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00002433#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f82007-06-24 18:30:48 +00002434 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002435 cFYI(1, "FCNTL cap");
Steve French75865f82007-06-24 18:30:48 +00002436 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002437 cFYI(1, "EXTATTR cap");
Steve French75865f82007-06-24 18:30:48 +00002438 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002439 cFYI(1, "POSIX path cap");
Steve French75865f82007-06-24 18:30:48 +00002440 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002441 cFYI(1, "XATTR cap");
Steve French75865f82007-06-24 18:30:48 +00002442 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002443 cFYI(1, "POSIX ACL cap");
Steve French75865f82007-06-24 18:30:48 +00002444 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002445 cFYI(1, "very large read cap");
Steve French75865f82007-06-24 18:30:48 +00002446 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002447 cFYI(1, "very large write cap");
Steve French8af18972007-02-14 04:42:51 +00002448#endif /* CIFS_DEBUG2 */
2449 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002450 if (vol_info == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002451 cFYI(1, "resetting capabilities failed");
Steve French442aa312007-09-24 20:25:46 +00002452 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00002453 cERROR(1, "Negotiating Unix capabilities "
Steve French5a44b312007-09-20 15:16:24 +00002454 "with the server failed. Consider "
2455 "mounting with the Unix Extensions\n"
2456 "disabled, if problems are found, "
2457 "by specifying the nounix mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00002458 "option.");
Steve French5a44b312007-09-20 15:16:24 +00002459
Steve French8af18972007-02-14 04:42:51 +00002460 }
2461 }
2462}
2463
Steve French03a143c2008-02-14 06:38:30 +00002464static void
2465convert_delimiter(char *path, char delim)
2466{
2467 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002468 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002469
2470 if (path == NULL)
2471 return;
2472
Steve French582d21e2008-05-13 04:54:12 +00002473 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002474 old_delim = '\\';
2475 else
2476 old_delim = '/';
2477
Steve French03a143c2008-02-14 06:38:30 +00002478 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002479 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002480 path[i] = delim;
2481 }
2482}
2483
Steve French3b795212008-11-13 19:45:32 +00002484static void setup_cifs_sb(struct smb_vol *pvolume_info,
2485 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002486{
Steve French3b795212008-11-13 19:45:32 +00002487 if (pvolume_info->rsize > CIFSMaxBufSize) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002488 cERROR(1, "rsize %d too large, using MaxBufSize",
2489 pvolume_info->rsize);
Steve French3b795212008-11-13 19:45:32 +00002490 cifs_sb->rsize = CIFSMaxBufSize;
2491 } else if ((pvolume_info->rsize) &&
2492 (pvolume_info->rsize <= CIFSMaxBufSize))
2493 cifs_sb->rsize = pvolume_info->rsize;
2494 else /* default */
2495 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002496
Steve French3b795212008-11-13 19:45:32 +00002497 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002498 cERROR(1, "wsize %d too large, using 4096 instead",
2499 pvolume_info->wsize);
Steve French3b795212008-11-13 19:45:32 +00002500 cifs_sb->wsize = 4096;
2501 } else if (pvolume_info->wsize)
2502 cifs_sb->wsize = pvolume_info->wsize;
2503 else
2504 cifs_sb->wsize = min_t(const int,
2505 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2506 127*1024);
2507 /* old default of CIFSMaxBufSize was too small now
2508 that SMB Write2 can send multiple pages in kvec.
2509 RFC1001 does not describe what happens when frame
2510 bigger than 128K is sent so use that as max in
2511 conjunction with 52K kvec constraint on arch with 4K
2512 page size */
2513
2514 if (cifs_sb->rsize < 2048) {
2515 cifs_sb->rsize = 2048;
2516 /* Windows ME may prefer this */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002517 cFYI(1, "readsize set to minimum: 2048");
Steve French3b795212008-11-13 19:45:32 +00002518 }
2519 /* calculate prepath */
2520 cifs_sb->prepath = pvolume_info->prepath;
2521 if (cifs_sb->prepath) {
2522 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2523 /* we can not convert the / to \ in the path
2524 separators in the prefixpath yet because we do not
2525 know (until reset_cifs_unix_caps is called later)
2526 whether POSIX PATH CAP is available. We normalize
2527 the / to \ after reset_cifs_unix_caps is called */
2528 pvolume_info->prepath = NULL;
2529 } else
2530 cifs_sb->prepathlen = 0;
2531 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2532 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2533 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2534 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002535 cFYI(1, "file mode: 0x%x dir mode: 0x%x",
2536 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
Steve French3b795212008-11-13 19:45:32 +00002537
2538 if (pvolume_info->noperm)
2539 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2540 if (pvolume_info->setuids)
2541 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2542 if (pvolume_info->server_ino)
2543 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2544 if (pvolume_info->remap)
2545 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2546 if (pvolume_info->no_xattr)
2547 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2548 if (pvolume_info->sfu_emul)
2549 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2550 if (pvolume_info->nobrl)
2551 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve Frenchbe652442009-02-23 15:21:59 +00002552 if (pvolume_info->nostrictsync)
Steve French4717bed2009-02-24 14:44:19 +00002553 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
Steve French13a6e422008-12-02 17:24:33 +00002554 if (pvolume_info->mand_lock)
2555 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002556 if (pvolume_info->cifs_acl)
2557 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2558 if (pvolume_info->override_uid)
2559 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2560 if (pvolume_info->override_gid)
2561 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2562 if (pvolume_info->dynperm)
2563 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Suresh Jayaramanfa1df752010-07-05 18:13:36 +05302564 if (pvolume_info->fsc)
2565 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
Steve French3b795212008-11-13 19:45:32 +00002566 if (pvolume_info->direct_io) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002567 cFYI(1, "mounting share using direct i/o");
Steve French3b795212008-11-13 19:45:32 +00002568 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2569 }
Stefan Metzmacher736a3322010-07-30 14:56:00 +02002570 if (pvolume_info->mfsymlinks) {
2571 if (pvolume_info->sfu_emul) {
2572 cERROR(1, "mount option mfsymlinks ignored if sfu "
2573 "mount option is used");
2574 } else {
2575 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
2576 }
2577 }
Steve French3b795212008-11-13 19:45:32 +00002578
2579 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
Joe Perchesb6b38f72010-04-21 03:50:45 +00002580 cERROR(1, "mount option dynperm ignored if cifsacl "
2581 "mount option supported");
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002582}
2583
Igor Mammedove4cce942009-02-10 14:10:26 +03002584static int
2585is_path_accessible(int xid, struct cifsTconInfo *tcon,
2586 struct cifs_sb_info *cifs_sb, const char *full_path)
2587{
2588 int rc;
Igor Mammedove4cce942009-02-10 14:10:26 +03002589 FILE_ALL_INFO *pfile_info;
2590
Igor Mammedove4cce942009-02-10 14:10:26 +03002591 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2592 if (pfile_info == NULL)
2593 return -ENOMEM;
2594
2595 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2596 0 /* not legacy */, cifs_sb->local_nls,
2597 cifs_sb->mnt_cifs_flags &
2598 CIFS_MOUNT_MAP_SPECIAL_CHR);
2599 kfree(pfile_info);
2600 return rc;
2601}
2602
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002603static void
2604cleanup_volume_info(struct smb_vol **pvolume_info)
2605{
2606 struct smb_vol *volume_info;
2607
Dan Carpenterad6cca62010-04-26 12:10:06 +02002608 if (!pvolume_info || !*pvolume_info)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002609 return;
2610
2611 volume_info = *pvolume_info;
2612 kzfree(volume_info->password);
2613 kfree(volume_info->UNC);
2614 kfree(volume_info->prepath);
2615 kfree(volume_info);
2616 *pvolume_info = NULL;
2617 return;
2618}
2619
Steve French2d6d5892009-04-09 00:36:44 +00002620#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002621/* build_path_to_root returns full path to root when
2622 * we do not have an exiting connection (tcon) */
2623static char *
2624build_unc_path_to_root(const struct smb_vol *volume_info,
2625 const struct cifs_sb_info *cifs_sb)
2626{
2627 char *full_path;
2628
2629 int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
2630 full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
2631 if (full_path == NULL)
2632 return ERR_PTR(-ENOMEM);
2633
2634 strncpy(full_path, volume_info->UNC, unc_len);
2635 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
2636 int i;
2637 for (i = 0; i < unc_len; i++) {
2638 if (full_path[i] == '\\')
2639 full_path[i] = '/';
2640 }
2641 }
2642
2643 if (cifs_sb->prepathlen)
2644 strncpy(full_path + unc_len, cifs_sb->prepath,
2645 cifs_sb->prepathlen);
2646
2647 full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
2648 return full_path;
2649}
Steve French2d6d5892009-04-09 00:36:44 +00002650#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652int
2653cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002654 char *mount_data_global, const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
Jeff Laytona2934c72009-12-03 08:09:41 -05002656 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002658 struct smb_vol *volume_info;
Jeff Laytona2934c72009-12-03 08:09:41 -05002659 struct cifsSesInfo *pSesInfo;
2660 struct cifsTconInfo *tcon;
2661 struct TCP_Server_Info *srvTcp;
Igor Mammedove4cce942009-02-10 14:10:26 +03002662 char *full_path;
Steve French2d6d5892009-04-09 00:36:44 +00002663 char *mount_data = mount_data_global;
Jeff Layton9d002df2010-10-06 19:51:11 -04002664 struct tcon_link *tlink;
Steve French2d6d5892009-04-09 00:36:44 +00002665#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002666 struct dfs_info3_param *referrals = NULL;
2667 unsigned int num_referrals = 0;
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002668 int referral_walks_count = 0;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002669try_mount_again:
Steve French2d6d5892009-04-09 00:36:44 +00002670#endif
Jeff Laytona2934c72009-12-03 08:09:41 -05002671 rc = 0;
2672 tcon = NULL;
2673 pSesInfo = NULL;
2674 srvTcp = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002675 full_path = NULL;
Jeff Layton9d002df2010-10-06 19:51:11 -04002676 tlink = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
2678 xid = GetXid();
2679
Jeff Layton7586b762008-12-01 18:41:49 -05002680 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2681 if (!volume_info) {
2682 rc = -ENOMEM;
2683 goto out;
2684 }
Steve French50c2f752007-07-13 00:33:32 +00002685
Jeff Layton7586b762008-12-01 18:41:49 -05002686 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002687 rc = -EINVAL;
2688 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 }
2690
Jeff Layton7586b762008-12-01 18:41:49 -05002691 if (volume_info->nullauth) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002692 cFYI(1, "null user");
Jeff Layton7586b762008-12-01 18:41:49 -05002693 volume_info->username = "";
2694 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 /* BB fixme parse for domain name here */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002696 cFYI(1, "Username: %s", volume_info->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002698 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002699 /* In userspace mount helper we can get user name from alternate
2700 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002701 rc = -EINVAL;
2702 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 }
2704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002706 if (volume_info->iocharset == NULL) {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002707 /* load_nls_default cannot return null */
2708 volume_info->local_nls = load_nls_default();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 } else {
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002710 volume_info->local_nls = load_nls(volume_info->iocharset);
2711 if (volume_info->local_nls == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002712 cERROR(1, "CIFS mount error: iocharset %s not found",
2713 volume_info->iocharset);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002714 rc = -ELIBACC;
2715 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 }
2717 }
Jeff Laytona5fc4ce2010-04-24 07:57:42 -04002718 cifs_sb->local_nls = volume_info->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Jeff Layton63c038c2008-12-01 18:41:46 -05002720 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002721 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002722 if (IS_ERR(srvTcp)) {
2723 rc = PTR_ERR(srvTcp);
2724 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 }
2726
Jeff Layton36988c72010-04-24 07:57:43 -04002727 /* get a reference to a SMB session */
2728 pSesInfo = cifs_get_smb_ses(srvTcp, volume_info);
2729 if (IS_ERR(pSesInfo)) {
2730 rc = PTR_ERR(pSesInfo);
2731 pSesInfo = NULL;
2732 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 }
Steve French50c2f752007-07-13 00:33:32 +00002734
Jeff Laytond00c28d2010-04-24 07:57:44 -04002735 setup_cifs_sb(volume_info, cifs_sb);
2736 if (pSesInfo->capabilities & CAP_LARGE_FILES)
2737 sb->s_maxbytes = MAX_LFS_FILESIZE;
2738 else
2739 sb->s_maxbytes = MAX_NON_LFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Steve French8af18972007-02-14 04:42:51 +00002741 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 sb->s_time_gran = 100;
2743
Jeff Laytond00c28d2010-04-24 07:57:44 -04002744 /* search for existing tcon to this server share */
2745 tcon = cifs_get_tcon(pSesInfo, volume_info);
2746 if (IS_ERR(tcon)) {
2747 rc = PTR_ERR(tcon);
2748 tcon = NULL;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002749 goto remote_path_check;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002750 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002751
Steve Frenchd82c2df2008-11-15 00:07:26 +00002752 /* do not care if following two calls succeed - informational */
2753 if (!tcon->ipc) {
2754 CIFSSMBQFSDeviceInfo(xid, tcon);
2755 CIFSSMBQFSAttributeInfo(xid, tcon);
2756 }
2757
2758 /* tell server which Unix caps we support */
2759 if (tcon->ses->capabilities & CAP_UNIX)
2760 /* reset of caps checks mount to see if unix extensions
2761 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002762 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002763 else
2764 tcon->unix_ext = 0; /* server does not support them */
2765
2766 /* convert forward to back slashes in prepath here if needed */
2767 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2768 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2769
2770 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2771 cifs_sb->rsize = 1024 * 127;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002772 cFYI(DBG2, "no very large read support, rsize now 127K");
Steve Frenchd82c2df2008-11-15 00:07:26 +00002773 }
2774 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2775 cifs_sb->wsize = min(cifs_sb->wsize,
2776 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2777 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2778 cifs_sb->rsize = min(cifs_sb->rsize,
2779 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002781remote_path_check:
2782 /* check if a whole path (including prepath) is not remote */
2783 if (!rc && cifs_sb->prepathlen && tcon) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002784 /* build_path_to_root works only when we have a valid tcon */
2785 full_path = cifs_build_path_to_root(cifs_sb);
2786 if (full_path == NULL) {
2787 rc = -ENOMEM;
2788 goto mount_fail_check;
2789 }
2790 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002791 if (rc != -EREMOTE) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002792 kfree(full_path);
2793 goto mount_fail_check;
2794 }
2795 kfree(full_path);
2796 }
2797
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002798 /* get referral if needed */
2799 if (rc == -EREMOTE) {
Steve Frenchd036f502009-04-03 03:12:08 +00002800#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002801 if (referral_walks_count > MAX_NESTED_LINKS) {
2802 /*
2803 * BB: when we implement proper loop detection,
2804 * we will remove this check. But now we need it
2805 * to prevent an indefinite loop if 'DFS tree' is
2806 * misconfigured (i.e. has loops).
2807 */
2808 rc = -ELOOP;
2809 goto mount_fail_check;
2810 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002811 /* convert forward to back slashes in prepath here if needed */
2812 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2813 convert_delimiter(cifs_sb->prepath,
2814 CIFS_DIR_SEP(cifs_sb));
2815 full_path = build_unc_path_to_root(volume_info, cifs_sb);
2816 if (IS_ERR(full_path)) {
2817 rc = PTR_ERR(full_path);
2818 goto mount_fail_check;
2819 }
2820
Joe Perchesb6b38f72010-04-21 03:50:45 +00002821 cFYI(1, "Getting referral for: %s", full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002822 rc = get_dfs_path(xid, pSesInfo , full_path + 1,
2823 cifs_sb->local_nls, &num_referrals, &referrals,
2824 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
2825 if (!rc && num_referrals > 0) {
2826 char *fake_devname = NULL;
2827
2828 if (mount_data != mount_data_global)
2829 kfree(mount_data);
Jeff Layton7b91e262009-07-23 15:22:30 -04002830
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002831 mount_data = cifs_compose_mount_options(
2832 cifs_sb->mountdata, full_path + 1,
2833 referrals, &fake_devname);
Jeff Layton7b91e262009-07-23 15:22:30 -04002834
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002835 free_dfs_info_array(referrals, num_referrals);
Jeff Layton7b91e262009-07-23 15:22:30 -04002836 kfree(fake_devname);
2837 kfree(full_path);
2838
2839 if (IS_ERR(mount_data)) {
2840 rc = PTR_ERR(mount_data);
2841 mount_data = NULL;
2842 goto mount_fail_check;
2843 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002844
2845 if (tcon)
2846 cifs_put_tcon(tcon);
2847 else if (pSesInfo)
2848 cifs_put_smb_ses(pSesInfo);
2849
2850 cleanup_volume_info(&volume_info);
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002851 referral_walks_count++;
Jeff Laytona2934c72009-12-03 08:09:41 -05002852 FreeXid(xid);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002853 goto try_mount_again;
2854 }
Steve Frenchd036f502009-04-03 03:12:08 +00002855#else /* No DFS support, return error on mount */
2856 rc = -EOPNOTSUPP;
2857#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002858 }
2859
Jeff Layton9d002df2010-10-06 19:51:11 -04002860 if (rc)
2861 goto mount_fail_check;
2862
2863 /* now, hang the tcon off of the superblock */
2864 tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
2865 if (tlink == NULL) {
2866 rc = -ENOMEM;
2867 goto mount_fail_check;
2868 }
2869
2870 tlink->tl_index = pSesInfo->linux_uid;
2871 tlink->tl_tcon = tcon;
2872 tlink->tl_time = jiffies;
2873 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2874 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2875
2876 rc = radix_tree_preload(GFP_KERNEL);
2877 if (rc == -ENOMEM) {
2878 kfree(tlink);
2879 goto mount_fail_check;
2880 }
2881
2882 spin_lock(&cifs_sb->tlink_tree_lock);
2883 radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
2884 radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
2885 CIFS_TLINK_MASTER_TAG);
2886 spin_unlock(&cifs_sb->tlink_tree_lock);
2887 radix_tree_preload_end();
2888
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002889mount_fail_check:
2890 /* on error free sesinfo and tcon struct if needed */
2891 if (rc) {
2892 if (mount_data != mount_data_global)
2893 kfree(mount_data);
2894 /* If find_unc succeeded then rc == 0 so we can not end */
2895 /* up accidently freeing someone elses tcon struct */
2896 if (tcon)
2897 cifs_put_tcon(tcon);
2898 else if (pSesInfo)
2899 cifs_put_smb_ses(pSesInfo);
2900 else
2901 cifs_put_tcp_session(srvTcp);
2902 goto out;
2903 }
2904
Jeff Layton7586b762008-12-01 18:41:49 -05002905 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 (in which case it is not needed anymore) but when new sesion is created
2907 the password ptr is put in the new session structure (in which case the
2908 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002909out:
2910 /* zero out password before freeing */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002911 cleanup_volume_info(&volume_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 FreeXid(xid);
2913 return rc;
2914}
2915
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916int
2917CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2918 const char *tree, struct cifsTconInfo *tcon,
2919 const struct nls_table *nls_codepage)
2920{
2921 struct smb_hdr *smb_buffer;
2922 struct smb_hdr *smb_buffer_response;
2923 TCONX_REQ *pSMB;
2924 TCONX_RSP *pSMBr;
2925 unsigned char *bcc_ptr;
2926 int rc = 0;
Jeff Laytoncc20c032009-04-30 07:16:21 -04002927 int length, bytes_left;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 __u16 count;
2929
2930 if (ses == NULL)
2931 return -EIO;
2932
2933 smb_buffer = cifs_buf_get();
Steve Frenchca43e3b2009-09-01 17:20:50 +00002934 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 return -ENOMEM;
Steve Frenchca43e3b2009-09-01 17:20:50 +00002936
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 smb_buffer_response = smb_buffer;
2938
2939 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2940 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07002941
2942 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 smb_buffer->Uid = ses->Suid;
2944 pSMB = (TCONX_REQ *) smb_buffer;
2945 pSMBr = (TCONX_RSP *) smb_buffer_response;
2946
2947 pSMB->AndXCommand = 0xFF;
2948 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002950 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08002951 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00002952 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08002953 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00002954 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08002955 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00002956 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08002957 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
2958 specified as required (when that support is added to
2959 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00002960 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08002961 by Samba (not sure whether other servers allow
2962 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00002963#ifdef CONFIG_CIFS_WEAK_PW_HASH
Jeff Layton04912d62010-04-24 07:57:45 -04002964 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05002965 (ses->server->secType == LANMAN))
2966 calc_lanman_hash(tcon->password, ses->server->cryptKey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05002967 ses->server->secMode &
2968 SECMODE_PW_ENCRYPT ? true : false,
2969 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00002970 else
2971#endif /* CIFS_WEAK_PW_HASH */
Jeff Layton00e485b2008-12-05 20:41:21 -05002972 SMBNTencrypt(tcon->password, ses->server->cryptKey,
Steve Frencheeac8042006-01-13 21:34:58 -08002973 bcc_ptr);
2974
Steve French7c7b25b2006-06-01 19:20:10 +00002975 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002976 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00002977 /* must align unicode strings */
2978 *bcc_ptr = 0; /* null byte password */
2979 bcc_ptr++;
2980 }
Steve Frencheeac8042006-01-13 21:34:58 -08002981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
Steve French50c2f752007-07-13 00:33:32 +00002983 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00002984 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2986
2987 if (ses->capabilities & CAP_STATUS32) {
2988 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2989 }
2990 if (ses->capabilities & CAP_DFS) {
2991 smb_buffer->Flags2 |= SMBFLG2_DFS;
2992 }
2993 if (ses->capabilities & CAP_UNICODE) {
2994 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2995 length =
Steve French50c2f752007-07-13 00:33:32 +00002996 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
2997 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00002998 (/* server len*/ + 256 /* share len */), nls_codepage);
2999 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 bcc_ptr += 2; /* skip trailing null */
3001 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 strcpy(bcc_ptr, tree);
3003 bcc_ptr += strlen(tree) + 1;
3004 }
3005 strcpy(bcc_ptr, "?????");
3006 bcc_ptr += strlen("?????");
3007 bcc_ptr += 1;
3008 count = bcc_ptr - &pSMB->Password[0];
3009 pSMB->hdr.smb_buf_length += count;
3010 pSMB->ByteCount = cpu_to_le16(count);
3011
Steve French133672e2007-11-13 22:41:37 +00003012 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3013 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 /* above now done in SendReceive */
3016 if ((rc == 0) && (tcon != NULL)) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003017 bool is_unicode;
3018
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003020 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 tcon->tid = smb_buffer_response->Tid;
3022 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003023 bytes_left = BCC(smb_buffer_response);
3024 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003025 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3026 is_unicode = true;
3027 else
3028 is_unicode = false;
3029
Jeff Laytoncc20c032009-04-30 07:16:21 -04003030
Steve French50c2f752007-07-13 00:33:32 +00003031 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003032 if (length == 3) {
3033 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3034 (bcc_ptr[2] == 'C')) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003035 cFYI(1, "IPC connection");
Steve French7f8ed422007-09-28 22:28:55 +00003036 tcon->ipc = 1;
3037 }
3038 } else if (length == 2) {
3039 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3040 /* the most common case */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003041 cFYI(1, "disk share connection");
Steve French7f8ed422007-09-28 22:28:55 +00003042 }
3043 }
Steve French50c2f752007-07-13 00:33:32 +00003044 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003045 bytes_left -= (length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003047
3048 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003049 kfree(tcon->nativeFileSystem);
Steve Frenchd185cda2009-04-30 17:45:10 +00003050 tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003051 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003052 nls_codepage);
3053
Joe Perchesb6b38f72010-04-21 03:50:45 +00003054 cFYI(1, "nativeFileSystem=%s", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003055
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003056 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003057 (smb_buffer_response->WordCount == 7))
3058 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003059 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3060 else
3061 tcon->Flags = 0;
Joe Perchesb6b38f72010-04-21 03:50:45 +00003062 cFYI(1, "Tcon flags: 0x%x ", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003064 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 ses->ipc_tid = smb_buffer_response->Tid;
3066 }
3067
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003068 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 return rc;
3070}
3071
3072int
3073cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3074{
Jeff Layton9d002df2010-10-06 19:51:11 -04003075 int i, ret;
Steve French50c2f752007-07-13 00:33:32 +00003076 char *tmp;
Jeff Layton9d002df2010-10-06 19:51:11 -04003077 struct tcon_link *tlink[8];
3078 unsigned long index = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
Jeff Layton9d002df2010-10-06 19:51:11 -04003080 do {
3081 spin_lock(&cifs_sb->tlink_tree_lock);
3082 ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
3083 (void **)tlink, index,
3084 ARRAY_SIZE(tlink));
3085 /* increment index for next pass */
3086 if (ret > 0)
3087 index = tlink[ret - 1]->tl_index + 1;
3088 for (i = 0; i < ret; i++) {
3089 cifs_get_tlink(tlink[i]);
3090 clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
3091 radix_tree_delete(&cifs_sb->tlink_tree,
3092 tlink[i]->tl_index);
3093 }
3094 spin_unlock(&cifs_sb->tlink_tree_lock);
Steve French50c2f752007-07-13 00:33:32 +00003095
Jeff Layton9d002df2010-10-06 19:51:11 -04003096 for (i = 0; i < ret; i++)
3097 cifs_put_tlink(tlink[i]);
3098 } while (ret != 0);
3099
Steve French2fe87f02006-09-21 07:02:52 +00003100 tmp = cifs_sb->prepath;
3101 cifs_sb->prepathlen = 0;
3102 cifs_sb->prepath = NULL;
3103 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
Jeff Layton9d002df2010-10-06 19:51:11 -04003105 return 0;
Steve French50c2f752007-07-13 00:33:32 +00003106}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
Jeff Layton198b5682010-04-24 07:57:48 -04003108int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109{
3110 int rc = 0;
Jeff Layton198b5682010-04-24 07:57:48 -04003111 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
Jeff Layton198b5682010-04-24 07:57:48 -04003113 /* only send once per connect */
3114 if (server->maxBuf != 0)
3115 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116
Jeff Layton198b5682010-04-24 07:57:48 -04003117 rc = CIFSSMBNegotiate(xid, ses);
3118 if (rc == -EAGAIN) {
3119 /* retry only once on 1st time connection */
3120 rc = CIFSSMBNegotiate(xid, ses);
3121 if (rc == -EAGAIN)
3122 rc = -EHOSTDOWN;
3123 }
3124 if (rc == 0) {
3125 spin_lock(&GlobalMid_Lock);
3126 if (server->tcpStatus != CifsExiting)
3127 server->tcpStatus = CifsGood;
3128 else
3129 rc = -EHOSTDOWN;
3130 spin_unlock(&GlobalMid_Lock);
3131
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 }
Steve French26b994f2008-08-06 05:11:33 +00003133
Jeff Layton198b5682010-04-24 07:57:48 -04003134 return rc;
3135}
Steve French26b994f2008-08-06 05:11:33 +00003136
Jeff Layton198b5682010-04-24 07:57:48 -04003137
3138int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
3139 struct nls_table *nls_info)
3140{
3141 int rc = 0;
3142 struct TCP_Server_Info *server = ses->server;
3143
3144 ses->flags = 0;
3145 ses->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003146 if (linuxExtEnabled == 0)
Jeff Layton198b5682010-04-24 07:57:48 -04003147 ses->capabilities &= (~CAP_UNIX);
Steve French20418ac2009-04-30 16:13:32 +00003148
Joe Perchesb6b38f72010-04-21 03:50:45 +00003149 cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
3150 server->secMode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003151
Jeff Layton198b5682010-04-24 07:57:48 -04003152 rc = CIFS_SessSetup(xid, ses, nls_info);
Steve French26b994f2008-08-06 05:11:33 +00003153 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003154 cERROR(1, "Send error in SessSetup = %d", rc);
Steve French26b994f2008-08-06 05:11:33 +00003155 } else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003156 cFYI(1, "CIFS Session Established successfully");
Steve French20418ac2009-04-30 16:13:32 +00003157 spin_lock(&GlobalMid_Lock);
Jeff Layton198b5682010-04-24 07:57:48 -04003158 ses->status = CifsGood;
3159 ses->need_reconnect = false;
Steve French20418ac2009-04-30 16:13:32 +00003160 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003161 }
3162
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 return rc;
3164}
3165
Jeff Layton9d002df2010-10-06 19:51:11 -04003166struct cifsTconInfo *
3167cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
3168{
3169 struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
3170 struct cifsSesInfo *ses;
3171 struct cifsTconInfo *tcon = NULL;
3172 struct smb_vol *vol_info;
3173 char username[MAX_USERNAME_SIZE + 1];
3174
3175 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
3176 if (vol_info == NULL) {
3177 tcon = ERR_PTR(-ENOMEM);
3178 goto out;
3179 }
3180
3181 snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
3182 vol_info->username = username;
3183 vol_info->local_nls = cifs_sb->local_nls;
3184 vol_info->linux_uid = fsuid;
3185 vol_info->cred_uid = fsuid;
3186 vol_info->UNC = master_tcon->treeName;
3187 vol_info->retry = master_tcon->retry;
3188 vol_info->nocase = master_tcon->nocase;
3189 vol_info->local_lease = master_tcon->local_lease;
3190 vol_info->no_linux_ext = !master_tcon->unix_ext;
3191
3192 /* FIXME: allow for other secFlg settings */
3193 vol_info->secFlg = CIFSSEC_MUST_KRB5;
3194
3195 /* get a reference for the same TCP session */
3196 write_lock(&cifs_tcp_ses_lock);
3197 ++master_tcon->ses->server->srv_count;
3198 write_unlock(&cifs_tcp_ses_lock);
3199
3200 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
3201 if (IS_ERR(ses)) {
3202 tcon = (struct cifsTconInfo *)ses;
3203 cifs_put_tcp_session(master_tcon->ses->server);
3204 goto out;
3205 }
3206
3207 tcon = cifs_get_tcon(ses, vol_info);
3208 if (IS_ERR(tcon)) {
3209 cifs_put_smb_ses(ses);
3210 goto out;
3211 }
3212
3213 if (ses->capabilities & CAP_UNIX)
3214 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
3215out:
3216 kfree(vol_info);
3217
3218 return tcon;
3219}
3220
3221static struct tcon_link *
3222cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
3223{
3224 struct tcon_link *tlink;
3225 unsigned int ret;
3226
3227 spin_lock(&cifs_sb->tlink_tree_lock);
3228 ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
3229 0, 1, CIFS_TLINK_MASTER_TAG);
3230 spin_unlock(&cifs_sb->tlink_tree_lock);
3231
3232 /* the master tcon should always be present */
3233 if (ret == 0)
3234 BUG();
3235
3236 return tlink;
3237}
3238
3239struct cifsTconInfo *
3240cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3241{
3242 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3243}
3244
3245static int
3246cifs_sb_tcon_pending_wait(void *unused)
3247{
3248 schedule();
3249 return signal_pending(current) ? -ERESTARTSYS : 0;
3250}
3251
3252/*
3253 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3254 * current task.
3255 *
3256 * If the superblock doesn't refer to a multiuser mount, then just return
3257 * the master tcon for the mount.
3258 *
3259 * First, search the radix tree for an existing tcon for this fsuid. If one
3260 * exists, then check to see if it's pending construction. If it is then wait
3261 * for construction to complete. Once it's no longer pending, check to see if
3262 * it failed and either return an error or retry construction, depending on
3263 * the timeout.
3264 *
3265 * If one doesn't exist then insert a new tcon_link struct into the tree and
3266 * try to construct a new one.
3267 */
3268struct tcon_link *
3269cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
3270{
3271 int ret;
3272 unsigned long fsuid = (unsigned long) current_fsuid();
3273 struct tcon_link *tlink, *newtlink;
3274
3275 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
3276 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3277
3278 spin_lock(&cifs_sb->tlink_tree_lock);
3279 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3280 if (tlink)
3281 cifs_get_tlink(tlink);
3282 spin_unlock(&cifs_sb->tlink_tree_lock);
3283
3284 if (tlink == NULL) {
3285 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
3286 if (newtlink == NULL)
3287 return ERR_PTR(-ENOMEM);
3288 newtlink->tl_index = fsuid;
3289 newtlink->tl_tcon = ERR_PTR(-EACCES);
3290 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
3291 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
3292 cifs_get_tlink(newtlink);
3293
3294 ret = radix_tree_preload(GFP_KERNEL);
3295 if (ret != 0) {
3296 kfree(newtlink);
3297 return ERR_PTR(ret);
3298 }
3299
3300 spin_lock(&cifs_sb->tlink_tree_lock);
3301 /* was one inserted after previous search? */
3302 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3303 if (tlink) {
3304 cifs_get_tlink(tlink);
3305 spin_unlock(&cifs_sb->tlink_tree_lock);
3306 radix_tree_preload_end();
3307 kfree(newtlink);
3308 goto wait_for_construction;
3309 }
3310 ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
3311 spin_unlock(&cifs_sb->tlink_tree_lock);
3312 radix_tree_preload_end();
3313 if (ret) {
3314 kfree(newtlink);
3315 return ERR_PTR(ret);
3316 }
3317 tlink = newtlink;
3318 } else {
3319wait_for_construction:
3320 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
3321 cifs_sb_tcon_pending_wait,
3322 TASK_INTERRUPTIBLE);
3323 if (ret) {
3324 cifs_put_tlink(tlink);
3325 return ERR_PTR(ret);
3326 }
3327
3328 /* if it's good, return it */
3329 if (!IS_ERR(tlink->tl_tcon))
3330 return tlink;
3331
3332 /* return error if we tried this already recently */
3333 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
3334 cifs_put_tlink(tlink);
3335 return ERR_PTR(-EACCES);
3336 }
3337
3338 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
3339 goto wait_for_construction;
3340 }
3341
3342 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
3343 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
3344 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
3345
3346 if (IS_ERR(tlink->tl_tcon)) {
3347 cifs_put_tlink(tlink);
3348 return ERR_PTR(-EACCES);
3349 }
3350
3351 return tlink;
3352}