blob: 6298dc32adebd999d22adb708319e6adef457624 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/pagemap.h>
27#include <linux/ctype.h>
28#include <linux/utsname.h>
29#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070030#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070031#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000032#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070033#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080034#include <linux/freezer.h>
Igor Mammedov5c2503a2009-04-21 19:31:05 +040035#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include <asm/processor.h>
Jeff Layton50b64e32009-06-02 06:55:20 -040038#include <linux/inet.h>
Steve French0e2beda2009-01-30 21:24:41 +000039#include <net/ipv6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "cifspdu.h"
41#include "cifsglob.h"
42#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
45#include "cifs_fs_sb.h"
46#include "ntlmssp.h"
47#include "nterr.h"
48#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080049#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#define CIFS_PORT 445
52#define RFC1001_PORT 139
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
55 unsigned char *p24);
56
57extern mempool_t *cifs_req_poolp;
58
59struct smb_vol {
60 char *username;
61 char *password;
62 char *domainname;
63 char *UNC;
64 char *UNCip;
Steve French95b1cb92008-05-15 16:44:38 +000065 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 uid_t linux_uid;
70 gid_t linux_gid;
71 mode_t file_mode;
72 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000073 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000074 bool rw:1;
75 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 unsigned int rsize;
102 unsigned int wsize;
103 unsigned int sockopt;
104 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000105 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106};
107
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500108static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500109static int ipv6_connect(struct TCP_Server_Info *server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Jeff Laytond5c56052008-12-01 18:42:33 -0500111/*
112 * cifs tcp session reconnection
113 *
114 * mark tcp session as reconnecting so temporarily locked
115 * mark all smb sessions as reconnecting for tcp session
116 * reconnect tcp session
117 * wake up waiters on reconnection? - (not needed currently)
118 */
Steve French2cd646a2006-09-28 19:43:08 +0000119static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120cifs_reconnect(struct TCP_Server_Info *server)
121{
122 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500123 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 struct cifsSesInfo *ses;
125 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000126 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000129 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000130 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 next time through the loop */
132 spin_unlock(&GlobalMid_Lock);
133 return rc;
134 } else
135 server->tcpStatus = CifsNeedReconnect;
136 spin_unlock(&GlobalMid_Lock);
137 server->maxBuf = 0;
138
Steve Frenche4eb2952005-04-28 22:41:09 -0700139 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* before reconnecting the tcp session, mark the smb session (uid)
142 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500143 read_lock(&cifs_tcp_ses_lock);
144 list_for_each(tmp, &server->smb_ses_list) {
145 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
146 ses->need_reconnect = true;
147 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500148 list_for_each(tmp2, &ses->tcon_list) {
149 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
150 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500153 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500155 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000156 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000157 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800159 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000160 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000161 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 server->ssocket->flags));
163 sock_release(server->ssocket);
164 server->ssocket = NULL;
165 }
166
167 spin_lock(&GlobalMid_Lock);
168 list_for_each(tmp, &server->pending_mid_q) {
169 mid_entry = list_entry(tmp, struct
170 mid_q_entry,
171 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000172 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700173 /* Mark other intransit requests as needing
174 retry so we do not immediately mark the
175 session bad again (ie after we reconnect
176 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000177 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
179 }
180 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500181 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Jeff Layton469ee612008-10-16 18:46:39 +0000183 while ((server->tcpStatus != CifsExiting) &&
184 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000185 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500186 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500187 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500188 else
189 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000190 if (rc) {
191 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700192 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 } else {
194 atomic_inc(&tcpSesReconnectCount);
195 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000196 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700198 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000199 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 /* atomic_set(&server->inFlight,0);*/
201 wake_up(&server->response_q);
202 }
203 }
204 return rc;
205}
206
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000207/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700208 return codes:
209 0 not a transact2, or all data present
210 >0 transact2 with that much data missing
211 -EINVAL = invalid transact2
212
213 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000214static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700215{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000216 struct smb_t2_rsp *pSMBt;
217 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700218 int data_in_this_rsp;
219 int remaining;
220
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000221 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700222 return 0;
223
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224 /* check for plausible wct, bcc and t2 data and parm sizes */
225 /* check for parm and data offset going beyond end of smb */
226 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000227 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700228 return -EINVAL;
229 }
230
231 pSMBt = (struct smb_t2_rsp *)pSMB;
232
233 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
234 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
235
236 remaining = total_data_size - data_in_this_rsp;
237
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000238 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000240 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000241 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700242 total_data_size, data_in_this_rsp));
243 return -EINVAL;
244 } else {
Steve French467a8f82007-06-27 22:41:32 +0000245 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700246 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000247 if (total_data_size > maxBufSize) {
248 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
249 total_data_size, maxBufSize));
250 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700251 }
252 return remaining;
253 }
254}
255
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000256static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700257{
258 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
259 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
260 int total_data_size;
261 int total_in_buf;
262 int remaining;
263 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000264 char *data_area_of_target;
265 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700266 __u16 byte_count;
267
268 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
269
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000270 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000271 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700272 }
273
274 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
275
276 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700279 return -EINVAL;
280
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700282 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000283
Steve Frenche4eb2952005-04-28 22:41:09 -0700284 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000285 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000286 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700287 }
288
289 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000290 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700291 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
292 /* validate target area */
293
294 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000295 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700296
297 data_area_of_target += total_in_buf;
298
299 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700301 total_in_buf += total_in_buf2;
302 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
303 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
304 byte_count += total_in_buf2;
305 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
306
Steve French70ca7342005-09-22 16:32:06 -0700307 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700308 byte_count += total_in_buf2;
309
310 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000311
Steve French70ca7342005-09-22 16:32:06 -0700312 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700313
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000314 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000315 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 return 0; /* we are done */
317 } else /* more responses to go */
318 return 1;
319
320}
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322static int
323cifs_demultiplex_thread(struct TCP_Server_Info *server)
324{
325 int length;
326 unsigned int pdu_length, total_read;
327 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700328 struct smb_hdr *bigbuf = NULL;
329 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 struct msghdr smb_msg;
331 struct kvec iov;
332 struct socket *csocket = server->ssocket;
333 struct list_head *tmp;
334 struct cifsSesInfo *ses;
335 struct task_struct *task_to_wake = NULL;
336 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700337 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000338 bool isLargeBuf = false;
339 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700340 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700343 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400344
345 length = atomic_inc_return(&tcpSesAllocCount);
346 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000347 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
348 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700350 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000351 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700352 if (try_to_freeze())
353 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700354 if (bigbuf == NULL) {
355 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000356 if (!bigbuf) {
357 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700358 msleep(3000);
359 /* retry will check if exiting */
360 continue;
361 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000362 } else if (isLargeBuf) {
363 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000364 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700366
367 if (smallbuf == NULL) {
368 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000369 if (!smallbuf) {
370 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700371 msleep(1000);
372 /* retry will check if exiting */
373 continue;
374 }
375 /* beginning of smb buffer is cleared in our buf_get */
376 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000377 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700378
Steve French4b18f2a2008-04-29 00:06:05 +0000379 isLargeBuf = false;
380 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700381 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 iov.iov_base = smb_buffer;
383 iov.iov_len = 4;
384 smb_msg.msg_control = NULL;
385 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000386 pdu_length = 4; /* enough to get RFC1001 header */
387incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 length =
389 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000390 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Jeff Layton469ee612008-10-16 18:46:39 +0000392 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 break;
394 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000395 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000397 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 csocket = server->ssocket;
399 continue;
400 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700401 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 allowing socket to clear and app threads to set
403 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000404 if (pdu_length < 4) {
405 iov.iov_base = (4 - pdu_length) +
406 (char *)smb_buffer;
407 iov.iov_len = pdu_length;
408 smb_msg.msg_control = NULL;
409 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000410 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000411 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000412 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000414 if (server->tcpStatus == CifsNew) {
415 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700416 /* some servers kill the TCP session rather than
417 returning an SMB negprot error, in which
418 case reconnecting here is not going to help,
419 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 break;
421 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000422 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000423 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
Steve French467a8f82007-06-27 22:41:32 +0000426 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700427 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 cifs_reconnect(server);
429 csocket = server->ssocket;
430 wake_up(&server->response_q);
431 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000432 } else if (length < pdu_length) {
433 cFYI(1, ("requested %d bytes but only got %d bytes",
434 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000435 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000436 msleep(1);
437 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Steve French67010fb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* The right amount was read from socket - 4 bytes */
441 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700442
Steve French70ca7342005-09-22 16:32:06 -0700443 /* the first byte big endian of the length field,
444 is actually not part of the length but the type
445 with the most common, zero, as regular data */
446 temp = *((char *) smb_buffer);
447
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700449 but we convert it here so it is always manipulated
450 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700451 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700452 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700453
Steve French467a8f82007-06-27 22:41:32 +0000454 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700455
456 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000459 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700460 continue;
Steve French70ca7342005-09-22 16:32:06 -0700461 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000462 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700463 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700465 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000466 if (server->tcpStatus == CifsNew) {
467 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700468 ret of smb negprot error) reconnecting
469 not going to help, ret error to mount */
470 break;
471 } else {
472 /* give server a second to
473 clean up before reconnect attempt */
474 msleep(1000);
475 /* always try 445 first on reconnect
476 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000477 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700478 since we do not begin with RFC1001
479 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000480 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700481 htons(CIFS_PORT);
482 cifs_reconnect(server);
483 csocket = server->ssocket;
484 wake_up(&server->response_q);
485 continue;
486 }
Steve French70ca7342005-09-22 16:32:06 -0700487 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700489 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
490 length);
Steve French46810cb2005-04-28 22:41:09 -0700491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700494 }
495
496 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000497 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000498 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700499 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700500 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 cifs_reconnect(server);
502 csocket = server->ssocket;
503 wake_up(&server->response_q);
504 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000505 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700506
507 /* else length ok */
508 reconnect = 0;
509
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000510 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000511 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 memcpy(bigbuf, smallbuf, 4);
513 smb_buffer = bigbuf;
514 }
515 length = 0;
516 iov.iov_base = 4 + (char *)smb_buffer;
517 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000518 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 total_read += length) {
520 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
521 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000522 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 (length == -EINTR)) {
524 /* then will exit */
525 reconnect = 2;
526 break;
527 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700528 cifs_reconnect(server);
529 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 /* Now we will reread sock */
532 reconnect = 1;
533 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 (length == -EAGAIN)) {
536 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000537 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 threads to set tcpStatus
539 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000540 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700541 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 pdu_length - total_read));
545 cifs_reconnect(server);
546 csocket = server->ssocket;
547 reconnect = 1;
548 break;
Steve French46810cb2005-04-28 22:41:09 -0700549 }
550 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000551 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700552 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000553 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700554 continue;
555
556 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000557
Steve Frenche4eb2952005-04-28 22:41:09 -0700558
559 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000560 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700561 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700562 continue;
563 }
564
565
566 task_to_wake = NULL;
567 spin_lock(&GlobalMid_Lock);
568 list_for_each(tmp, &server->pending_mid_q) {
569 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
570
Steve French50c2f752007-07-13 00:33:32 +0000571 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700572 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
573 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000576 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000577 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000579 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000581 mid_entry->multiRsp =
582 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 break;
584 } else {
585 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000586 mid_entry->multiEnd =
587 true;
Steve French50c2f752007-07-13 00:33:32 +0000588 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 }
590 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000591 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 cERROR(1,("1st trans2 resp needs bigbuf"));
593 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000594 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700596 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 mid_entry->resp_buf =
598 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000599 mid_entry->largeBuf =
600 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 bigbuf = NULL;
602 }
603 }
604 break;
Steve French50c2f752007-07-13 00:33:32 +0000605 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700606 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000607 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700608multi_t2_fnd:
609 task_to_wake = mid_entry->tsk;
610 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700611#ifdef CONFIG_CIFS_STATS2
612 mid_entry->when_received = jiffies;
613#endif
Steve French3a5ff612006-07-14 22:37:11 +0000614 /* so we do not time out requests to server
615 which is still responding (since server could
616 be busy but not dead) */
617 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700618 break;
619 }
620 }
621 spin_unlock(&GlobalMid_Lock);
622 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700623 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000624 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700625 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000626 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700627 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000628 else
Steve Frenchcd634992005-04-28 22:41:10 -0700629 smallbuf = NULL;
630 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700631 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000632 } else if (!is_valid_oplock_break(smb_buffer, server) &&
633 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000634 cERROR(1, ("No task to wake, unknown frame received! "
635 "NumMids %d", midCount.counter));
636 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700637 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000638#ifdef CONFIG_CIFS_DEBUG2
639 cifs_dump_detail(smb_buffer);
640 cifs_dump_mids(server);
641#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000642
Steve Frenche4eb2952005-04-28 22:41:09 -0700643 }
644 } /* end while !EXITING */
645
Jeff Laytone7ddee92008-11-14 13:44:38 -0500646 /* take it off the list, if it's not already */
647 write_lock(&cifs_tcp_ses_lock);
648 list_del_init(&server->tcp_ses_list);
649 write_unlock(&cifs_tcp_ses_lock);
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 spin_lock(&GlobalMid_Lock);
652 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000653 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000654 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000655
Steve French31ca3bc2005-04-28 22:41:11 -0700656 /* check if we have blocked requests that need to free */
657 /* Note that cifs_max_pending is normally 50, but
658 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000659 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000660 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700661 atomic_set(&server->inFlight, cifs_max_pending - 1);
662 /* We do not want to set the max_pending too low or we
663 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000665 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700667 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 to the same server - they now will see the session is in exit state
669 and get out of SendReceive. */
670 wake_up_all(&server->request_q);
671 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700672 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000673
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000674 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 sock_release(csocket);
676 server->ssocket = NULL;
677 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000679 cifs_buf_release(bigbuf);
680 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700681 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jeff Layton14fbf502008-11-14 13:53:46 -0500683 /*
684 * BB: we shouldn't have to do any of this. It shouldn't be
685 * possible to exit from the thread with active SMB sessions
686 */
687 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700689 /* loop through server session structures attached to this and
690 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500691 list_for_each(tmp, &server->smb_ses_list) {
692 ses = list_entry(tmp, struct cifsSesInfo,
693 smb_ses_list);
694 ses->status = CifsExiting;
695 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500697 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500702 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700703 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500704 smb_ses_list);
705 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 spin_lock(&GlobalMid_Lock);
709 list_for_each(tmp, &server->pending_mid_q) {
710 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
711 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000712 cFYI(1, ("Clearing Mid 0x%x - waking up ",
713 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000715 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
718 }
719 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500720 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700722 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724
Steve Frenchf1914012005-08-18 09:37:34 -0700725 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000726 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700728 /* due to delays on oplock break requests, we need
729 to wait at least 45 seconds before giving up
730 on a request getting a response and going ahead
731 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700733 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* if threads still have not exited they are probably never
735 coming home not much else we can do but free the memory */
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Steve French31ca3bc2005-04-28 22:41:11 -0700738 /* last chance to mark ses pointers invalid
739 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000740 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700741 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500742 /* BB: This shouldn't be necessary, see above */
743 read_lock(&cifs_tcp_ses_lock);
744 list_for_each(tmp, &server->smb_ses_list) {
745 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
746 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700747 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500748 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700749
Jeff Laytonc359cf32007-11-16 22:22:06 +0000750 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400751 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700752 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400753
754 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000755 if (length > 0)
756 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
757 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000758
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400759 /* if server->tsk was NULL then wait for a signal before exiting */
760 if (!task_to_wake) {
761 set_current_state(TASK_INTERRUPTIBLE);
762 while (!signal_pending(current)) {
763 schedule();
764 set_current_state(TASK_INTERRUPTIBLE);
765 }
766 set_current_state(TASK_RUNNING);
767 }
768
Jeff Layton0468a2c2008-12-01 07:09:35 -0500769 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
Jeff Laytonc359cf32007-11-16 22:22:06 +0000772/* extract the host portion of the UNC string */
773static char *
774extract_hostname(const char *unc)
775{
776 const char *src;
777 char *dst, *delim;
778 unsigned int len;
779
780 /* skip double chars at beginning of string */
781 /* BB: check validity of these bytes? */
782 src = unc + 2;
783
784 /* delimiter between hostname and sharename is always '\\' now */
785 delim = strchr(src, '\\');
786 if (!delim)
787 return ERR_PTR(-EINVAL);
788
789 len = delim - src;
790 dst = kmalloc((len + 1), GFP_KERNEL);
791 if (dst == NULL)
792 return ERR_PTR(-ENOMEM);
793
794 memcpy(dst, src, len);
795 dst[len] = '\0';
796
797 return dst;
798}
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800static int
Steve French50c2f752007-07-13 00:33:32 +0000801cifs_parse_mount_options(char *options, const char *devname,
802 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 char *value;
805 char *data;
806 unsigned int temp_len, i, j;
807 char separator[2];
808
809 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000810 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000813 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000814 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700815 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000816 int n = strnlen(nodename, 15);
817 memset(vol->source_rfc1001_name, 0x20, 15);
818 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000819 /* does not have to be perfect mapping since field is
820 informational, only used for servers that do not support
821 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700822 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700826 /* null target name indicates to use *SMBSERVR default called name
827 if we end up sending RFC1001 session initialize */
828 vol->target_rfc1001_name[0] = 0;
David Howellsa001e5b2008-11-14 10:38:47 +1100829 vol->linux_uid = current_uid(); /* use current_euid() instead? */
830 vol->linux_gid = current_gid();
Jeff Laytonf55ed1a2009-05-26 16:28:11 -0400831
832 /* default to only allowing write access to owner of the mount */
833 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000836 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700837 /* default is always to request posix paths. */
838 vol->posix_paths = 1;
Jeff Laytona0c92172009-05-27 15:40:47 -0400839 /* default to using server inode numbers where available */
840 vol->server_ino = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -0700841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (!options)
843 return 1;
844
Steve French50c2f752007-07-13 00:33:32 +0000845 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000846 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 separator[0] = options[4];
848 options += 5;
849 } else {
Steve French467a8f82007-06-27 22:41:32 +0000850 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852 }
Steve French50c2f752007-07-13 00:33:32 +0000853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 while ((data = strsep(&options, separator)) != NULL) {
855 if (!*data)
856 continue;
857 if ((value = strchr(data, '=')) != NULL)
858 *value++ = '\0';
859
Steve French50c2f752007-07-13 00:33:32 +0000860 /* Have to parse this before we parse for "user" */
861 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000863 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 vol->no_xattr = 1;
865 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000866 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 printk(KERN_WARNING
868 "CIFS: invalid or missing username\n");
869 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000870 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000871 /* null user, ie anonymous, authentication */
872 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
874 if (strnlen(value, 200) < 200) {
875 vol->username = value;
876 } else {
877 printk(KERN_WARNING "CIFS: username too long\n");
878 return 1;
879 }
880 } else if (strnicmp(data, "pass", 4) == 0) {
881 if (!value) {
882 vol->password = NULL;
883 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 /* check if string begins with double comma
886 since that would mean the password really
887 does start with a comma, and would not
888 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000889 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 vol->password = NULL;
891 continue;
892 }
893 }
894 temp_len = strlen(value);
895 /* removed password length check, NTLM passwords
896 can be arbitrarily long */
897
Steve French50c2f752007-07-13 00:33:32 +0000898 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 prematurely null terminated. Commas in password are
900 specified across the cifs mount interface by a double
901 comma ie ,, and a comma used as in other cases ie ','
902 as a parameter delimiter/separator is single and due
903 to the strsep above is temporarily zeroed. */
904
905 /* NB: password legally can have multiple commas and
906 the only illegal character in a password is null */
907
Steve French50c2f752007-07-13 00:33:32 +0000908 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700909 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* reinsert comma */
911 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000912 temp_len += 2; /* move after second comma */
913 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000915 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700916 separator[0]) {
917 /* skip second comma */
918 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000919 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 /* single comma indicating start
921 of next parm */
922 break;
923 }
924 }
925 temp_len++;
926 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000927 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 options = NULL;
929 } else {
930 value[temp_len] = 0;
931 /* point option to start of next parm */
932 options = value + temp_len + 1;
933 }
Steve French50c2f752007-07-13 00:33:32 +0000934 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 double commas to singles. Note that this ends up
936 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700937 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000938 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000939 printk(KERN_WARNING "CIFS: no memory "
940 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700941 return 1;
942 }
Steve French50c2f752007-07-13 00:33:32 +0000943 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000945 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700946 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* skip second comma */
948 i++;
949 }
950 }
951 vol->password[j] = 0;
952 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700953 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000954 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000955 printk(KERN_WARNING "CIFS: no memory "
956 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700957 return 1;
958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 strcpy(vol->password, value);
960 }
Jeff Layton58f7f682009-06-10 09:57:55 -0400961 } else if (!strnicmp(data, "ip", 2) ||
962 !strnicmp(data, "addr", 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if (!value || !*value) {
964 vol->UNCip = NULL;
Jeff Layton50b64e32009-06-02 06:55:20 -0400965 } else if (strnlen(value, INET6_ADDRSTRLEN) <
966 INET6_ADDRSTRLEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 vol->UNCip = value;
968 } else {
Steve French50c2f752007-07-13 00:33:32 +0000969 printk(KERN_WARNING "CIFS: ip address "
970 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 return 1;
972 }
Steve French50c2f752007-07-13 00:33:32 +0000973 } else if (strnicmp(data, "sec", 3) == 0) {
974 if (!value || !*value) {
975 cERROR(1, ("no security value specified"));
976 continue;
977 } else if (strnicmp(value, "krb5i", 5) == 0) {
978 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000979 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800980 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000981 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
982 CIFSSEC_MAY_KRB5; */
983 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800984 return 1;
985 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000986 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchac683922009-05-06 04:16:04 +0000987#ifdef CONFIG_CIFS_EXPERIMENTAL
988 } else if (strnicmp(value, "ntlmsspi", 8) == 0) {
989 vol->secFlg |= CIFSSEC_MAY_NTLMSSP |
990 CIFSSEC_MUST_SIGN;
991 } else if (strnicmp(value, "ntlmssp", 7) == 0) {
992 vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
993#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800994 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000995 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000996 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800997 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000998 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800999 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001000 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +00001001 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -08001002 } else if (strnicmp(value, "ntlm", 4) == 0) {
1003 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +00001004 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -08001005 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001006 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +00001007 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +00001008#ifdef CONFIG_CIFS_WEAK_PW_HASH
1009 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001010 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001011#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001012 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001013 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001014 } else {
1015 cERROR(1, ("bad security option: %s", value));
1016 return 1;
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else if ((strnicmp(data, "unc", 3) == 0)
1019 || (strnicmp(data, "target", 6) == 0)
1020 || (strnicmp(data, "path", 4) == 0)) {
1021 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001022 printk(KERN_WARNING "CIFS: invalid path to "
1023 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 1; /* needs_arg; */
1025 }
1026 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001027 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001028 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001030 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (strncmp(vol->UNC, "//", 2) == 0) {
1032 vol->UNC[0] = '\\';
1033 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001034 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001036 "CIFS: UNC Path does not begin "
1037 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 1;
1039 }
1040 } else {
1041 printk(KERN_WARNING "CIFS: UNC name too long\n");
1042 return 1;
1043 }
1044 } else if ((strnicmp(data, "domain", 3) == 0)
1045 || (strnicmp(data, "workgroup", 5) == 0)) {
1046 if (!value || !*value) {
1047 printk(KERN_WARNING "CIFS: invalid domain name\n");
1048 return 1; /* needs_arg; */
1049 }
1050 /* BB are there cases in which a comma can be valid in
1051 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001052 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 vol->domainname = value;
1054 cFYI(1, ("Domain name set"));
1055 } else {
Steve French50c2f752007-07-13 00:33:32 +00001056 printk(KERN_WARNING "CIFS: domain name too "
1057 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return 1;
1059 }
Steve French50c2f752007-07-13 00:33:32 +00001060 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1061 if (!value || !*value) {
1062 printk(KERN_WARNING
1063 "CIFS: invalid path prefix\n");
1064 return 1; /* needs_argument */
1065 }
1066 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001067 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001068 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001069 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1070 if (vol->prepath == NULL)
1071 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001072 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001073 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001074 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001075 } else
Steve French50c2f752007-07-13 00:33:32 +00001076 strcpy(vol->prepath, value);
1077 cFYI(1, ("prefix path %s", vol->prepath));
1078 } else {
1079 printk(KERN_WARNING "CIFS: prefix too long\n");
1080 return 1;
1081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 } else if (strnicmp(data, "iocharset", 9) == 0) {
1083 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001084 printk(KERN_WARNING "CIFS: invalid iocharset "
1085 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return 1; /* needs_arg; */
1087 }
1088 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001089 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001091 /* if iocharset not set then load_nls_default
1092 is used by caller */
1093 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 } else {
Steve French63135e02007-07-17 17:34:02 +00001095 printk(KERN_WARNING "CIFS: iocharset name "
1096 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return 1;
1098 }
1099 } else if (strnicmp(data, "uid", 3) == 0) {
Jeff Layton4ae15072009-05-24 18:45:15 -04001100 if (value && *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 vol->linux_uid =
1102 simple_strtoul(value, &value, 0);
Jeff Layton4ae15072009-05-24 18:45:15 -04001103 } else if (strnicmp(data, "forceuid", 8) == 0) {
Steve French4523cc32007-04-30 20:13:06 +00001104 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 } else if (strnicmp(data, "gid", 3) == 0) {
Jeff Layton4ae15072009-05-24 18:45:15 -04001106 if (value && *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 vol->linux_gid =
1108 simple_strtoul(value, &value, 0);
Jeff Layton4ae15072009-05-24 18:45:15 -04001109 } else if (strnicmp(data, "forcegid", 8) == 0) {
Steve French4523cc32007-04-30 20:13:06 +00001110 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 } else if (strnicmp(data, "file_mode", 4) == 0) {
1112 if (value && *value) {
1113 vol->file_mode =
1114 simple_strtoul(value, &value, 0);
1115 }
1116 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1117 if (value && *value) {
1118 vol->dir_mode =
1119 simple_strtoul(value, &value, 0);
1120 }
1121 } else if (strnicmp(data, "dirmode", 4) == 0) {
1122 if (value && *value) {
1123 vol->dir_mode =
1124 simple_strtoul(value, &value, 0);
1125 }
1126 } else if (strnicmp(data, "port", 4) == 0) {
1127 if (value && *value) {
1128 vol->port =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "rsize", 5) == 0) {
1132 if (value && *value) {
1133 vol->rsize =
1134 simple_strtoul(value, &value, 0);
1135 }
1136 } else if (strnicmp(data, "wsize", 5) == 0) {
1137 if (value && *value) {
1138 vol->wsize =
1139 simple_strtoul(value, &value, 0);
1140 }
1141 } else if (strnicmp(data, "sockopt", 5) == 0) {
1142 if (value && *value) {
1143 vol->sockopt =
1144 simple_strtoul(value, &value, 0);
1145 }
1146 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1147 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001148 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 } else {
Steve French50c2f752007-07-13 00:33:32 +00001150 memset(vol->source_rfc1001_name, 0x20, 15);
1151 for (i = 0; i < 15; i++) {
1152 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 valid in this workstation netbios name (and need
1154 special handling)? */
1155
1156 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001157 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
Steve French50c2f752007-07-13 00:33:32 +00001159 else
1160 vol->source_rfc1001_name[i] =
1161 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 /* The string has 16th byte zero still from
1164 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001165 if ((i == 15) && (value[i] != 0))
1166 printk(KERN_WARNING "CIFS: netbiosname"
1167 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001168 }
1169 } else if (strnicmp(data, "servern", 7) == 0) {
1170 /* servernetbiosname specified override *SMBSERVER */
1171 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001172 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001173 } else {
1174 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001175 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001176
Steve French50c2f752007-07-13 00:33:32 +00001177 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001178 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001179 valid in this workstation netbios name
1180 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001181
Steve French50c2f752007-07-13 00:33:32 +00001182 /* user or mount helper must uppercase
1183 the netbiosname */
1184 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001185 break;
1186 else
Steve French50c2f752007-07-13 00:33:32 +00001187 vol->target_rfc1001_name[i] =
1188 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001189 }
1190 /* The string has 16th byte zero still from
1191 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001192 if ((i == 15) && (value[i] != 0))
1193 printk(KERN_WARNING "CIFS: server net"
1194 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 }
1196 } else if (strnicmp(data, "credentials", 4) == 0) {
1197 /* ignore */
1198 } else if (strnicmp(data, "version", 3) == 0) {
1199 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001200 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 /* ignore */
1202 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001203 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001204 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1205 vol->noblocksnd = 1;
1206 } else if (strnicmp(data, "noautotune", 10) == 0) {
1207 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 } else if ((strnicmp(data, "suid", 4) == 0) ||
1209 (strnicmp(data, "nosuid", 6) == 0) ||
1210 (strnicmp(data, "exec", 4) == 0) ||
1211 (strnicmp(data, "noexec", 6) == 0) ||
1212 (strnicmp(data, "nodev", 5) == 0) ||
1213 (strnicmp(data, "noauto", 6) == 0) ||
1214 (strnicmp(data, "dev", 3) == 0)) {
1215 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001216 uses these opts to set flags, and the flags are read
1217 by the kernel vfs layer before we get here (ie
1218 before read super) so there is no point trying to
1219 parse these options again and set anything and it
1220 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 continue;
1222 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001223 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 } else if (strnicmp(data, "hard", 4) == 0) {
1225 vol->retry = 1;
1226 } else if (strnicmp(data, "soft", 4) == 0) {
1227 vol->retry = 0;
1228 } else if (strnicmp(data, "perm", 4) == 0) {
1229 vol->noperm = 0;
1230 } else if (strnicmp(data, "noperm", 6) == 0) {
1231 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001232 } else if (strnicmp(data, "mapchars", 8) == 0) {
1233 vol->remap = 1;
1234 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1235 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if (strnicmp(data, "sfu", 3) == 0) {
1237 vol->sfu_emul = 1;
1238 } else if (strnicmp(data, "nosfu", 5) == 0) {
1239 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001240 } else if (strnicmp(data, "nodfs", 5) == 0) {
1241 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001242 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1243 vol->posix_paths = 1;
1244 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1245 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001246 } else if (strnicmp(data, "nounix", 6) == 0) {
1247 vol->no_linux_ext = 1;
1248 } else if (strnicmp(data, "nolinux", 7) == 0) {
1249 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001250 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001251 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001252 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001253 } else if (strnicmp(data, "brl", 3) == 0) {
1254 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001255 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001256 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001257 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001258 /* turn off mandatory locking in mode
1259 if remote locking is turned off since the
1260 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001261 if (vol->file_mode ==
1262 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001263 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001264 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1265 /* will take the shorter form "forcemand" as well */
1266 /* This mount option will force use of mandatory
1267 (DOS/Windows style) byte range locks, instead of
1268 using posix advisory byte range locks, even if the
1269 Unix extensions are available and posix locks would
1270 be supported otherwise. If Unix extensions are not
1271 negotiated this has no effect since mandatory locks
1272 would be used (mandatory locks is all that those
1273 those servers support) */
1274 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 } else if (strnicmp(data, "setuids", 7) == 0) {
1276 vol->setuids = 1;
1277 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1278 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001279 } else if (strnicmp(data, "dynperm", 7) == 0) {
1280 vol->dynperm = true;
1281 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1282 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 } else if (strnicmp(data, "nohard", 6) == 0) {
1284 vol->retry = 0;
1285 } else if (strnicmp(data, "nosoft", 6) == 0) {
1286 vol->retry = 1;
1287 } else if (strnicmp(data, "nointr", 6) == 0) {
1288 vol->intr = 0;
1289 } else if (strnicmp(data, "intr", 4) == 0) {
1290 vol->intr = 1;
Steve Frenchbe652442009-02-23 15:21:59 +00001291 } else if (strnicmp(data, "nostrictsync", 12) == 0) {
1292 vol->nostrictsync = 1;
1293 } else if (strnicmp(data, "strictsync", 10) == 0) {
1294 vol->nostrictsync = 0;
Steve French50c2f752007-07-13 00:33:32 +00001295 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001297 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001299 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001300 vol->cifs_acl = 1;
1301 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1302 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001303 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001305 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001307#ifdef CONFIG_CIFS_EXPERIMENTAL
1308 } else if (strnicmp(data, "locallease", 6) == 0) {
1309 vol->local_lease = 1;
1310#endif
Steve French50c2f752007-07-13 00:33:32 +00001311 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001312 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001313 } else if (strnicmp(data, "seal", 4) == 0) {
1314 /* we do not do the following in secFlags because seal
1315 is a per tree connection (mount) not a per socket
1316 or per-smb connection option in the protocol */
1317 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1318 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001319 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001321 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001323 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (!value || !*value) {
1325 vol->in6_addr = NULL;
1326 } else if (strnlen(value, 49) == 48) {
1327 vol->in6_addr = value;
1328 } else {
Steve French50c2f752007-07-13 00:33:32 +00001329 printk(KERN_WARNING "CIFS: ip v6 address not "
1330 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 return 1;
1332 }
1333 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001334 printk(KERN_WARNING "CIFS: Mount option noac not "
1335 "supported. Instead set "
1336 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 } else
Steve French50c2f752007-07-13 00:33:32 +00001338 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1339 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 }
1341 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001342 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001343 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1344 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 return 1;
1346 }
1347 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001348 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001349 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001351 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (strncmp(vol->UNC, "//", 2) == 0) {
1353 vol->UNC[0] = '\\';
1354 vol->UNC[1] = '\\';
1355 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001356 printk(KERN_WARNING "CIFS: UNC Path does not "
1357 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 return 1;
1359 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001360 value = strpbrk(vol->UNC+2, "/\\");
1361 if (value)
1362 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 } else {
1364 printk(KERN_WARNING "CIFS: UNC name too long\n");
1365 return 1;
1366 }
1367 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001368 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 vol->UNCip = &vol->UNC[2];
1370
1371 return 0;
1372}
1373
Jeff Laytone7ddee92008-11-14 13:44:38 -05001374static struct TCP_Server_Info *
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001375cifs_find_tcp_session(struct sockaddr_storage *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001378 struct TCP_Server_Info *server;
1379 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1380 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Jeff Laytone7ddee92008-11-14 13:44:38 -05001382 write_lock(&cifs_tcp_ses_lock);
1383 list_for_each(tmp, &cifs_tcp_ses_list) {
1384 server = list_entry(tmp, struct TCP_Server_Info,
1385 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001386 /*
1387 * the demux thread can exit on its own while still in CifsNew
1388 * so don't accept any sockets in that state. Since the
1389 * tcpStatus never changes back to CifsNew it's safe to check
1390 * for this without a lock.
1391 */
1392 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001393 continue;
Steve French50c2f752007-07-13 00:33:32 +00001394
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001395 if (addr->ss_family == AF_INET &&
Jeff Laytone7ddee92008-11-14 13:44:38 -05001396 (addr4->sin_addr.s_addr !=
1397 server->addr.sockAddr.sin_addr.s_addr))
1398 continue;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001399 else if (addr->ss_family == AF_INET6 &&
Steve French0e2beda2009-01-30 21:24:41 +00001400 !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
1401 &addr6->sin6_addr))
Jeff Laytone7ddee92008-11-14 13:44:38 -05001402 continue;
Steve French50c2f752007-07-13 00:33:32 +00001403
Jeff Laytone7ddee92008-11-14 13:44:38 -05001404 ++server->srv_count;
1405 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001406 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001407 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001409 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 return NULL;
1411}
1412
Jeff Layton14fbf502008-11-14 13:53:46 -05001413static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001414cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001416 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Jeff Laytone7ddee92008-11-14 13:44:38 -05001418 write_lock(&cifs_tcp_ses_lock);
1419 if (--server->srv_count > 0) {
1420 write_unlock(&cifs_tcp_ses_lock);
1421 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001423
Jeff Laytone7ddee92008-11-14 13:44:38 -05001424 list_del_init(&server->tcp_ses_list);
1425 write_unlock(&cifs_tcp_ses_lock);
1426
1427 spin_lock(&GlobalMid_Lock);
1428 server->tcpStatus = CifsExiting;
1429 spin_unlock(&GlobalMid_Lock);
1430
1431 task = xchg(&server->tsk, NULL);
1432 if (task)
1433 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434}
1435
Jeff Layton63c038c2008-12-01 18:41:46 -05001436static struct TCP_Server_Info *
1437cifs_get_tcp_session(struct smb_vol *volume_info)
1438{
1439 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001440 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05001441 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1442 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1443 int rc;
1444
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001445 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05001446
1447 if (volume_info->UNCip && volume_info->UNC) {
1448 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1449 &sin_server->sin_addr.s_addr);
1450
1451 if (rc <= 0) {
1452 /* not ipv4 address, try ipv6 */
1453 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1454 &sin_server6->sin6_addr.in6_u);
1455 if (rc > 0)
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001456 addr.ss_family = AF_INET6;
Jeff Layton63c038c2008-12-01 18:41:46 -05001457 } else {
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001458 addr.ss_family = AF_INET;
Jeff Layton63c038c2008-12-01 18:41:46 -05001459 }
1460
1461 if (rc <= 0) {
1462 /* we failed translating address */
1463 rc = -EINVAL;
1464 goto out_err;
1465 }
1466
1467 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1468 volume_info->UNCip));
1469 } else if (volume_info->UNCip) {
1470 /* BB using ip addr as tcp_ses name to connect to the
1471 DFS root below */
1472 cERROR(1, ("Connecting to DFS root not implemented yet"));
1473 rc = -EINVAL;
1474 goto out_err;
1475 } else /* which tcp_sess DFS root would we conect to */ {
1476 cERROR(1,
1477 ("CIFS mount error: No UNC path (e.g. -o "
1478 "unc=//192.168.1.100/public) specified"));
1479 rc = -EINVAL;
1480 goto out_err;
1481 }
1482
1483 /* see if we already have a matching tcp_ses */
1484 tcp_ses = cifs_find_tcp_session(&addr);
1485 if (tcp_ses)
1486 return tcp_ses;
1487
1488 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1489 if (!tcp_ses) {
1490 rc = -ENOMEM;
1491 goto out_err;
1492 }
1493
1494 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1495 if (IS_ERR(tcp_ses->hostname)) {
1496 rc = PTR_ERR(tcp_ses->hostname);
1497 goto out_err;
1498 }
1499
1500 tcp_ses->noblocksnd = volume_info->noblocksnd;
1501 tcp_ses->noautotune = volume_info->noautotune;
1502 atomic_set(&tcp_ses->inFlight, 0);
1503 init_waitqueue_head(&tcp_ses->response_q);
1504 init_waitqueue_head(&tcp_ses->request_q);
1505 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1506 mutex_init(&tcp_ses->srv_mutex);
1507 memcpy(tcp_ses->workstation_RFC1001_name,
1508 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1509 memcpy(tcp_ses->server_RFC1001_name,
1510 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1511 tcp_ses->sequence_number = 0;
1512 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1513 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1514
1515 /*
1516 * at this point we are the only ones with the pointer
1517 * to the struct since the kernel thread not created yet
1518 * no need to spinlock this init of tcpStatus or srv_count
1519 */
1520 tcp_ses->tcpStatus = CifsNew;
1521 ++tcp_ses->srv_count;
1522
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001523 if (addr.ss_family == AF_INET6) {
Jeff Layton63c038c2008-12-01 18:41:46 -05001524 cFYI(1, ("attempting ipv6 connect"));
1525 /* BB should we allow ipv6 on port 139? */
1526 /* other OS never observed in Wild doing 139 with v6 */
1527 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1528 sizeof(struct sockaddr_in6));
1529 sin_server6->sin6_port = htons(volume_info->port);
Jeff Laytond5c56052008-12-01 18:42:33 -05001530 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001531 } else {
1532 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1533 sizeof(struct sockaddr_in));
1534 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001535 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001536 }
1537 if (rc < 0) {
1538 cERROR(1, ("Error connecting to socket. Aborting operation"));
1539 goto out_err;
1540 }
1541
1542 /*
1543 * since we're in a cifs function already, we know that
1544 * this will succeed. No need for try_module_get().
1545 */
1546 __module_get(THIS_MODULE);
1547 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1548 tcp_ses, "cifsd");
1549 if (IS_ERR(tcp_ses->tsk)) {
1550 rc = PTR_ERR(tcp_ses->tsk);
1551 cERROR(1, ("error %d create cifsd thread", rc));
1552 module_put(THIS_MODULE);
1553 goto out_err;
1554 }
1555
1556 /* thread spawned, put it on the list */
1557 write_lock(&cifs_tcp_ses_lock);
1558 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1559 write_unlock(&cifs_tcp_ses_lock);
1560
1561 return tcp_ses;
1562
1563out_err:
1564 if (tcp_ses) {
1565 kfree(tcp_ses->hostname);
1566 if (tcp_ses->ssocket)
1567 sock_release(tcp_ses->ssocket);
1568 kfree(tcp_ses);
1569 }
1570 return ERR_PTR(rc);
1571}
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573static struct cifsSesInfo *
Jeff Layton14fbf502008-11-14 13:53:46 -05001574cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575{
1576 struct list_head *tmp;
1577 struct cifsSesInfo *ses;
1578
Jeff Layton14fbf502008-11-14 13:53:46 -05001579 write_lock(&cifs_tcp_ses_lock);
1580 list_for_each(tmp, &server->smb_ses_list) {
1581 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1582 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 continue;
1584
Jeff Layton14fbf502008-11-14 13:53:46 -05001585 ++ses->ses_count;
1586 write_unlock(&cifs_tcp_ses_lock);
1587 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001589 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return NULL;
1591}
1592
Jeff Layton14fbf502008-11-14 13:53:46 -05001593static void
1594cifs_put_smb_ses(struct cifsSesInfo *ses)
1595{
1596 int xid;
1597 struct TCP_Server_Info *server = ses->server;
1598
1599 write_lock(&cifs_tcp_ses_lock);
1600 if (--ses->ses_count > 0) {
1601 write_unlock(&cifs_tcp_ses_lock);
1602 return;
1603 }
1604
1605 list_del_init(&ses->smb_ses_list);
1606 write_unlock(&cifs_tcp_ses_lock);
1607
1608 if (ses->status == CifsGood) {
1609 xid = GetXid();
1610 CIFSSMBLogoff(xid, ses);
1611 _FreeXid(xid);
1612 }
1613 sesInfoFree(ses);
1614 cifs_put_tcp_session(server);
1615}
1616
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001618cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
1620 struct list_head *tmp;
1621 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Jeff Laytonf1987b42008-11-15 11:12:47 -05001623 write_lock(&cifs_tcp_ses_lock);
1624 list_for_each(tmp, &ses->tcon_list) {
1625 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1626 if (tcon->tidStatus == CifsExiting)
1627 continue;
1628 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 continue;
1630
Jeff Laytonf1987b42008-11-15 11:12:47 -05001631 ++tcon->tc_count;
1632 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 return tcon;
1634 }
Jeff Laytonf1987b42008-11-15 11:12:47 -05001635 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 return NULL;
1637}
1638
Jeff Laytonf1987b42008-11-15 11:12:47 -05001639static void
1640cifs_put_tcon(struct cifsTconInfo *tcon)
1641{
1642 int xid;
1643 struct cifsSesInfo *ses = tcon->ses;
1644
1645 write_lock(&cifs_tcp_ses_lock);
1646 if (--tcon->tc_count > 0) {
1647 write_unlock(&cifs_tcp_ses_lock);
1648 return;
1649 }
1650
1651 list_del_init(&tcon->tcon_list);
1652 write_unlock(&cifs_tcp_ses_lock);
1653
1654 xid = GetXid();
1655 CIFSSMBTDis(xid, tcon);
1656 _FreeXid(xid);
1657
1658 DeleteTconOplockQEntries(tcon);
1659 tconInfoFree(tcon);
1660 cifs_put_smb_ses(ses);
1661}
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663int
Steve French50c2f752007-07-13 00:33:32 +00001664get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1665 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001666 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
1668 char *temp_unc;
1669 int rc = 0;
1670
1671 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001672 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674 if (pSesInfo->ipc_tid == 0) {
1675 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001676 strnlen(pSesInfo->serverName,
1677 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 + 1 + 4 /* slash IPC$ */ + 2,
1679 GFP_KERNEL);
1680 if (temp_unc == NULL)
1681 return -ENOMEM;
1682 temp_unc[0] = '\\';
1683 temp_unc[1] = '\\';
1684 strcpy(temp_unc + 2, pSesInfo->serverName);
1685 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1686 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1687 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001688 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 kfree(temp_unc);
1690 }
1691 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001692 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001693 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001694 /* BB map targetUNCs to dfs_info3 structures, here or
1695 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 return rc;
1698}
1699
Jeff Layton09e50d52008-07-23 10:11:19 -04001700#ifdef CONFIG_DEBUG_LOCK_ALLOC
1701static struct lock_class_key cifs_key[2];
1702static struct lock_class_key cifs_slock_key[2];
1703
1704static inline void
1705cifs_reclassify_socket4(struct socket *sock)
1706{
1707 struct sock *sk = sock->sk;
1708 BUG_ON(sock_owned_by_user(sk));
1709 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1710 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1711}
1712
1713static inline void
1714cifs_reclassify_socket6(struct socket *sock)
1715{
1716 struct sock *sk = sock->sk;
1717 BUG_ON(sock_owned_by_user(sk));
1718 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1719 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1720}
1721#else
1722static inline void
1723cifs_reclassify_socket4(struct socket *sock)
1724{
1725}
1726
1727static inline void
1728cifs_reclassify_socket6(struct socket *sock)
1729{
1730}
1731#endif
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001734static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
Steve French50c2f752007-07-13 00:33:32 +00001736 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve French50c2f752007-07-13 00:33:32 +00001738 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 /* mask a nibble at a time and encode */
1740 target[j] = 'A' + (0x0F & (source[i] >> 4));
1741 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001742 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 }
1744
1745}
1746
1747
1748static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001749ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
1751 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001752 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001754 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001756 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001757 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001758 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001760 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001763
1764 /* BB other socket options to set KEEPALIVE, NODELAY? */
1765 cFYI(1, ("Socket created"));
1766 server->ssocket = socket;
1767 socket->sk->sk_allocation = GFP_NOFS;
1768 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
1770
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001771 /* user overrode default port */
1772 if (server->addr.sockAddr.sin_port) {
1773 rc = socket->ops->connect(socket, (struct sockaddr *)
1774 &server->addr.sockAddr,
1775 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001777 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001780 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001781 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001783 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001786 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1787 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1788 rc = socket->ops->connect(socket,
1789 (struct sockaddr *)
1790 &server->addr.sockAddr,
1791 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001793 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 }
1795 }
1796 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001797 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1798 rc = socket->ops->connect(socket, (struct sockaddr *)
1799 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001800 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001801 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001802 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804
1805 /* give up here - unless we want to retry on different
1806 protocol families some day */
1807 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001808 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001809 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001810 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001811 sock_release(socket);
1812 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 return rc;
1814 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001815
1816
1817 /*
1818 * Eventually check for other socket options to change from
1819 * the default. sock_setsockopt not used because it expects
1820 * user space buffer
1821 */
1822 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001823 socket->sk->sk_sndtimeo = 5 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001824
Steve Frenchb387eae2005-10-10 14:21:15 -07001825 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001826 if (server->noautotune) {
1827 if (socket->sk->sk_sndbuf < (200 * 1024))
1828 socket->sk->sk_sndbuf = 200 * 1024;
1829 if (socket->sk->sk_rcvbuf < (140 * 1024))
1830 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001833 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1834 socket->sk->sk_sndbuf,
1835 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001838 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001840 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001842 struct rfc1002_session_packet *ses_init_buf;
1843 struct smb_hdr *smb_buf;
1844 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1845 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001846 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001848 if (server->server_RFC1001_name &&
1849 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001850 rfc1002mangle(ses_init_buf->trailer.
1851 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001852 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001853 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001854 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001855 rfc1002mangle(ses_init_buf->trailer.
1856 session_req.called_name,
1857 DEFAULT_CIFS_CALLED_NAME,
1858 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001859
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* calling name ends in null (byte 16) from old smb
1863 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001864 if (server->workstation_RFC1001_name &&
1865 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001866 rfc1002mangle(ses_init_buf->trailer.
1867 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001868 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001869 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001870 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001871 rfc1002mangle(ses_init_buf->trailer.
1872 session_req.calling_name,
1873 "LINUX_CIFS_CLNT",
1874 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 ses_init_buf->trailer.session_req.scope1 = 0;
1877 ses_init_buf->trailer.session_req.scope2 = 0;
1878 smb_buf = (struct smb_hdr *)ses_init_buf;
1879 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1880 smb_buf->smb_buf_length = 0x81000044;
Jeff Layton0496e022008-12-30 12:39:16 -05001881 rc = smb_send(server, smb_buf, 0x44);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001883 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001884 requires very short break before negprot
1885 presumably because not expecting negprot
1886 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001887 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001888 complicating the code and causes no
1889 significant slowing down on mount
1890 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 }
Steve French50c2f752007-07-13 00:33:32 +00001892 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 }
Steve French50c2f752007-07-13 00:33:32 +00001896
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 return rc;
1898}
1899
1900static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001901ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902{
1903 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001904 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001906 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Jeff Laytond5c56052008-12-01 18:42:33 -05001908 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001909 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001910 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001912 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001913 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001916
1917 /* BB other socket options to set KEEPALIVE, NODELAY? */
1918 cFYI(1, ("ipv6 Socket created"));
1919 server->ssocket = socket;
1920 socket->sk->sk_allocation = GFP_NOFS;
1921 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923
Jeff Laytond5c56052008-12-01 18:42:33 -05001924 /* user overrode default port */
1925 if (server->addr.sockAddr6.sin6_port) {
1926 rc = socket->ops->connect(socket,
1927 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001928 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001930 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001933 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001934 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 later if fall back ports fail this time */
1936
Jeff Laytond5c56052008-12-01 18:42:33 -05001937 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001939 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1940 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1941 rc = socket->ops->connect(socket, (struct sockaddr *)
1942 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001943 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001945 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
1947 }
1948 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001949 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1950 rc = socket->ops->connect(socket, (struct sockaddr *)
1951 &server->addr.sockAddr6,
1952 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001953 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001954 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
1956
1957 /* give up here - unless we want to retry on different
1958 protocol families some day */
1959 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001960 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001961 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001962 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001963 sock_release(socket);
1964 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 return rc;
1966 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001967
Jeff Laytond5c56052008-12-01 18:42:33 -05001968 /*
1969 * Eventually check for other socket options to change from
1970 * the default. sock_setsockopt not used because it expects
1971 * user space buffer
1972 */
1973 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001974 socket->sk->sk_sndtimeo = 5 * HZ;
Jeff Laytond5c56052008-12-01 18:42:33 -05001975 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 return rc;
1978}
1979
Steve French50c2f752007-07-13 00:33:32 +00001980void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1981 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001982{
1983 /* if we are reconnecting then should we check to see if
1984 * any requested capabilities changed locally e.g. via
1985 * remount but we can not do much about it here
1986 * if they have (even if we could detect it by the following)
1987 * Perhaps we could add a backpointer to array of sb from tcon
1988 * or if we change to make all sb to same share the same
1989 * sb as NFS - then we only have one backpointer to sb.
1990 * What if we wanted to mount the server share twice once with
1991 * and once without posixacls or posix paths? */
1992 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001993
Steve Frenchc18c8422007-07-18 23:21:09 +00001994 if (vol_info && vol_info->no_linux_ext) {
1995 tcon->fsUnixInfo.Capability = 0;
1996 tcon->unix_ext = 0; /* Unix Extensions disabled */
1997 cFYI(1, ("Linux protocol extensions disabled"));
1998 return;
1999 } else if (vol_info)
2000 tcon->unix_ext = 1; /* Unix Extensions supported */
2001
2002 if (tcon->unix_ext == 0) {
2003 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
2004 return;
2005 }
Steve French50c2f752007-07-13 00:33:32 +00002006
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002007 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002008 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002009
Steve French8af18972007-02-14 04:42:51 +00002010 /* check for reconnect case in which we do not
2011 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002012 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002013 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00002014 originally at mount time */
2015 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2016 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002017 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2018 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2019 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00002020 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002021 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2022 cERROR(1, ("possible reconnect error"));
2023 cERROR(1,
2024 ("server disabled POSIX path support"));
2025 }
Steve French8af18972007-02-14 04:42:51 +00002026 }
Steve French50c2f752007-07-13 00:33:32 +00002027
Steve French8af18972007-02-14 04:42:51 +00002028 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002029 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002030 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002031 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002032 cFYI(1, ("negotiated posix acl support"));
2033 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002034 sb->s_flags |= MS_POSIXACL;
2035 }
2036
Steve French75865f8c2007-06-24 18:30:48 +00002037 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002038 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002039 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002040 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002041 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002042 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002043 CIFS_MOUNT_POSIX_PATHS;
2044 }
Steve French50c2f752007-07-13 00:33:32 +00002045
Steve French984acfe2007-04-26 16:42:50 +00002046 /* We might be setting the path sep back to a different
2047 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002048 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002049 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002050 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002051
2052 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2053 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2054 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002055 cFYI(DBG2,
2056 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002057 }
2058 }
Steve French50c2f752007-07-13 00:33:32 +00002059
2060
2061 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002062#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002063 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002064 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002065 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002066 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002067 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002068 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002069 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002070 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002071 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002072 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002073 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002074 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002075 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002076 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002077#endif /* CIFS_DEBUG2 */
2078 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002079 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002080 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002081 } else
Steve French5a44b312007-09-20 15:16:24 +00002082 cERROR(1, ("Negotiating Unix capabilities "
2083 "with the server failed. Consider "
2084 "mounting with the Unix Extensions\n"
2085 "disabled, if problems are found, "
2086 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002087 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002088
Steve French8af18972007-02-14 04:42:51 +00002089 }
2090 }
2091}
2092
Steve French03a143c2008-02-14 06:38:30 +00002093static void
2094convert_delimiter(char *path, char delim)
2095{
2096 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002097 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002098
2099 if (path == NULL)
2100 return;
2101
Steve French582d21e2008-05-13 04:54:12 +00002102 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002103 old_delim = '\\';
2104 else
2105 old_delim = '/';
2106
Steve French03a143c2008-02-14 06:38:30 +00002107 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002108 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002109 path[i] = delim;
2110 }
2111}
2112
Steve French3b795212008-11-13 19:45:32 +00002113static void setup_cifs_sb(struct smb_vol *pvolume_info,
2114 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002115{
Steve French3b795212008-11-13 19:45:32 +00002116 if (pvolume_info->rsize > CIFSMaxBufSize) {
2117 cERROR(1, ("rsize %d too large, using MaxBufSize",
2118 pvolume_info->rsize));
2119 cifs_sb->rsize = CIFSMaxBufSize;
2120 } else if ((pvolume_info->rsize) &&
2121 (pvolume_info->rsize <= CIFSMaxBufSize))
2122 cifs_sb->rsize = pvolume_info->rsize;
2123 else /* default */
2124 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002125
Steve French3b795212008-11-13 19:45:32 +00002126 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2127 cERROR(1, ("wsize %d too large, using 4096 instead",
2128 pvolume_info->wsize));
2129 cifs_sb->wsize = 4096;
2130 } else if (pvolume_info->wsize)
2131 cifs_sb->wsize = pvolume_info->wsize;
2132 else
2133 cifs_sb->wsize = min_t(const int,
2134 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2135 127*1024);
2136 /* old default of CIFSMaxBufSize was too small now
2137 that SMB Write2 can send multiple pages in kvec.
2138 RFC1001 does not describe what happens when frame
2139 bigger than 128K is sent so use that as max in
2140 conjunction with 52K kvec constraint on arch with 4K
2141 page size */
2142
2143 if (cifs_sb->rsize < 2048) {
2144 cifs_sb->rsize = 2048;
2145 /* Windows ME may prefer this */
2146 cFYI(1, ("readsize set to minimum: 2048"));
2147 }
2148 /* calculate prepath */
2149 cifs_sb->prepath = pvolume_info->prepath;
2150 if (cifs_sb->prepath) {
2151 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2152 /* we can not convert the / to \ in the path
2153 separators in the prefixpath yet because we do not
2154 know (until reset_cifs_unix_caps is called later)
2155 whether POSIX PATH CAP is available. We normalize
2156 the / to \ after reset_cifs_unix_caps is called */
2157 pvolume_info->prepath = NULL;
2158 } else
2159 cifs_sb->prepathlen = 0;
2160 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2161 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2162 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2163 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2164 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2165 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2166
2167 if (pvolume_info->noperm)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2169 if (pvolume_info->setuids)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2171 if (pvolume_info->server_ino)
2172 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2173 if (pvolume_info->remap)
2174 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2175 if (pvolume_info->no_xattr)
2176 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2177 if (pvolume_info->sfu_emul)
2178 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2179 if (pvolume_info->nobrl)
2180 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve Frenchbe652442009-02-23 15:21:59 +00002181 if (pvolume_info->nostrictsync)
Steve French4717bed2009-02-24 14:44:19 +00002182 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
Steve French13a6e422008-12-02 17:24:33 +00002183 if (pvolume_info->mand_lock)
2184 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002185 if (pvolume_info->cifs_acl)
2186 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2187 if (pvolume_info->override_uid)
2188 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2189 if (pvolume_info->override_gid)
2190 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2191 if (pvolume_info->dynperm)
2192 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2193 if (pvolume_info->direct_io) {
2194 cFYI(1, ("mounting share using direct i/o"));
2195 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2196 }
2197
2198 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2199 cERROR(1, ("mount option dynperm ignored if cifsacl "
2200 "mount option supported"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002201}
2202
Igor Mammedove4cce942009-02-10 14:10:26 +03002203static int
2204is_path_accessible(int xid, struct cifsTconInfo *tcon,
2205 struct cifs_sb_info *cifs_sb, const char *full_path)
2206{
2207 int rc;
2208 __u64 inode_num;
2209 FILE_ALL_INFO *pfile_info;
2210
2211 rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
2212 cifs_sb->local_nls,
2213 cifs_sb->mnt_cifs_flags &
2214 CIFS_MOUNT_MAP_SPECIAL_CHR);
2215 if (rc != -EOPNOTSUPP)
2216 return rc;
2217
2218 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2219 if (pfile_info == NULL)
2220 return -ENOMEM;
2221
2222 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2223 0 /* not legacy */, cifs_sb->local_nls,
2224 cifs_sb->mnt_cifs_flags &
2225 CIFS_MOUNT_MAP_SPECIAL_CHR);
2226 kfree(pfile_info);
2227 return rc;
2228}
2229
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002230static void
2231cleanup_volume_info(struct smb_vol **pvolume_info)
2232{
2233 struct smb_vol *volume_info;
2234
2235 if (!pvolume_info && !*pvolume_info)
2236 return;
2237
2238 volume_info = *pvolume_info;
2239 kzfree(volume_info->password);
2240 kfree(volume_info->UNC);
2241 kfree(volume_info->prepath);
2242 kfree(volume_info);
2243 *pvolume_info = NULL;
2244 return;
2245}
2246
Steve French2d6d5892009-04-09 00:36:44 +00002247#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002248/* build_path_to_root returns full path to root when
2249 * we do not have an exiting connection (tcon) */
2250static char *
2251build_unc_path_to_root(const struct smb_vol *volume_info,
2252 const struct cifs_sb_info *cifs_sb)
2253{
2254 char *full_path;
2255
2256 int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
2257 full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
2258 if (full_path == NULL)
2259 return ERR_PTR(-ENOMEM);
2260
2261 strncpy(full_path, volume_info->UNC, unc_len);
2262 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
2263 int i;
2264 for (i = 0; i < unc_len; i++) {
2265 if (full_path[i] == '\\')
2266 full_path[i] = '/';
2267 }
2268 }
2269
2270 if (cifs_sb->prepathlen)
2271 strncpy(full_path + unc_len, cifs_sb->prepath,
2272 cifs_sb->prepathlen);
2273
2274 full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
2275 return full_path;
2276}
Steve French2d6d5892009-04-09 00:36:44 +00002277#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279int
2280cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002281 char *mount_data_global, const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
2283 int rc = 0;
2284 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002285 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 struct cifsTconInfo *tcon = NULL;
2288 struct TCP_Server_Info *srvTcp = NULL;
Igor Mammedove4cce942009-02-10 14:10:26 +03002289 char *full_path;
Steve French2d6d5892009-04-09 00:36:44 +00002290 char *mount_data = mount_data_global;
2291#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002292 struct dfs_info3_param *referrals = NULL;
2293 unsigned int num_referrals = 0;
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002294 int referral_walks_count = 0;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002295try_mount_again:
Steve French2d6d5892009-04-09 00:36:44 +00002296#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002297 full_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 xid = GetXid();
2300
Jeff Layton7586b762008-12-01 18:41:49 -05002301 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2302 if (!volume_info) {
2303 rc = -ENOMEM;
2304 goto out;
2305 }
Steve French50c2f752007-07-13 00:33:32 +00002306
Jeff Layton7586b762008-12-01 18:41:49 -05002307 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002308 rc = -EINVAL;
2309 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 }
2311
Jeff Layton7586b762008-12-01 18:41:49 -05002312 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002313 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002314 volume_info->username = "";
2315 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002317 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002319 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002320 /* In userspace mount helper we can get user name from alternate
2321 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002322 rc = -EINVAL;
2323 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
2325
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
2327 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002328 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 cifs_sb->local_nls = load_nls_default();
2330 /* load_nls_default can not return null */
2331 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002332 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002333 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002334 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002335 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002336 rc = -ELIBACC;
2337 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339 }
2340
Jeff Layton63c038c2008-12-01 18:41:46 -05002341 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002342 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002343 if (IS_ERR(srvTcp)) {
2344 rc = PTR_ERR(srvTcp);
2345 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
2347
Jeff Layton7586b762008-12-01 18:41:49 -05002348 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002349 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002350 cFYI(1, ("Existing smb sess found (status=%d)",
2351 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002352 /*
2353 * The existing SMB session already has a reference to srvTcp,
2354 * so we can put back the extra one we got before
2355 */
2356 cifs_put_tcp_session(srvTcp);
2357
Steve French88e7d702008-01-03 17:37:09 +00002358 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002359 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002360 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002361 rc = cifs_setup_session(xid, pSesInfo,
2362 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002363 }
Steve French88e7d702008-01-03 17:37:09 +00002364 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002366 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002368 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002370 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 }
2372
Jeff Layton14fbf502008-11-14 13:53:46 -05002373 /* new SMB session uses our srvTcp ref */
2374 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002375 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Linus Torvalds0191b622008-12-28 12:49:40 -08002376 sprintf(pSesInfo->serverName, "%pI6",
2377 &srvTcp->addr.sockAddr6.sin6_addr);
Jeff Layton8ecaf672008-12-01 15:23:50 -05002378 else
Linus Torvalds0191b622008-12-28 12:49:40 -08002379 sprintf(pSesInfo->serverName, "%pI4",
2380 &srvTcp->addr.sockAddr.sin_addr.s_addr);
Jeff Layton14fbf502008-11-14 13:53:46 -05002381
2382 write_lock(&cifs_tcp_ses_lock);
2383 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2384 write_unlock(&cifs_tcp_ses_lock);
2385
Jeff Layton7586b762008-12-01 18:41:49 -05002386 /* volume_info->password freed at unmount */
2387 if (volume_info->password) {
Jeff Layton00e485b2008-12-05 20:41:21 -05002388 pSesInfo->password = kstrdup(volume_info->password,
2389 GFP_KERNEL);
2390 if (!pSesInfo->password) {
2391 rc = -ENOMEM;
2392 goto mount_fail_check;
2393 }
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002394 }
Jeff Layton7586b762008-12-01 18:41:49 -05002395 if (volume_info->username)
2396 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002397 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002398 if (volume_info->domainname) {
2399 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002400 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2401 if (pSesInfo->domainName)
2402 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002403 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002404 }
Jeff Layton7586b762008-12-01 18:41:49 -05002405 pSesInfo->linux_uid = volume_info->linux_uid;
2406 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002407 down(&pSesInfo->sesSem);
2408
2409 /* BB FIXME need to pass vol->secFlgs BB */
2410 rc = cifs_setup_session(xid, pSesInfo,
2411 cifs_sb->local_nls);
2412 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 }
Steve French50c2f752007-07-13 00:33:32 +00002414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* search for existing tcon to this server share */
2416 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002417 setup_cifs_sb(volume_info, cifs_sb);
Steve French0ae0efa2005-10-10 10:57:19 -07002418
Jeff Layton7586b762008-12-01 18:41:49 -05002419 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002421 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002422 /* existing tcon already has a reference */
2423 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002424 if (tcon->seal != volume_info->seal)
Steve French95b1cb92008-05-15 16:44:38 +00002425 cERROR(1, ("transport encryption setting "
2426 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 } else {
2428 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002429 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002431 goto mount_fail_check;
2432 }
Jeff Layton00e485b2008-12-05 20:41:21 -05002433
Steve Frenchab3f9922008-11-17 16:03:00 +00002434 tcon->ses = pSesInfo;
Jeff Layton00e485b2008-12-05 20:41:21 -05002435 if (volume_info->password) {
2436 tcon->password = kstrdup(volume_info->password,
2437 GFP_KERNEL);
2438 if (!tcon->password) {
2439 rc = -ENOMEM;
2440 goto mount_fail_check;
2441 }
2442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Jeff Layton7586b762008-12-01 18:41:49 -05002444 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2445 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002446 cERROR(1, ("Missing share name"));
Steve French3b795212008-11-13 19:45:32 +00002447 rc = -ENODEV;
2448 goto mount_fail_check;
2449 } else {
2450 /* BB Do we need to wrap sesSem around
2451 * this TCon call and Unix SetFS as
2452 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002453 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002454 tcon, cifs_sb->local_nls);
2455 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002456 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002457 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2458 cFYI(1, ("DFS disabled (%d)",
2459 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
2461 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002462 if (rc)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002463 goto remote_path_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002464 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002465 write_lock(&cifs_tcp_ses_lock);
2466 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2467 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
Steve French3b795212008-11-13 19:45:32 +00002469
2470 /* we can have only one retry value for a connection
2471 to a share so for resources mounted more than once
2472 to the same server share the last value passed in
2473 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002474 tcon->retry = volume_info->retry;
2475 tcon->nocase = volume_info->nocase;
2476 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
Steve French4523cc32007-04-30 20:13:06 +00002478 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2480 sb->s_maxbytes = (u64) 1 << 63;
2481 } else
2482 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2483 }
2484
Steve French8af18972007-02-14 04:42:51 +00002485 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 sb->s_time_gran = 100;
2487
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002488 if (rc)
2489 goto remote_path_check;
2490
Steve Frenchd82c2df2008-11-15 00:07:26 +00002491 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002492
2493 /* do not care if following two calls succeed - informational */
2494 if (!tcon->ipc) {
2495 CIFSSMBQFSDeviceInfo(xid, tcon);
2496 CIFSSMBQFSAttributeInfo(xid, tcon);
2497 }
2498
2499 /* tell server which Unix caps we support */
2500 if (tcon->ses->capabilities & CAP_UNIX)
2501 /* reset of caps checks mount to see if unix extensions
2502 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002503 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002504 else
2505 tcon->unix_ext = 0; /* server does not support them */
2506
2507 /* convert forward to back slashes in prepath here if needed */
2508 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2509 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2510
2511 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2512 cifs_sb->rsize = 1024 * 127;
2513 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2514 }
2515 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2516 cifs_sb->wsize = min(cifs_sb->wsize,
2517 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2518 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2519 cifs_sb->rsize = min(cifs_sb->rsize,
2520 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002522remote_path_check:
2523 /* check if a whole path (including prepath) is not remote */
2524 if (!rc && cifs_sb->prepathlen && tcon) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002525 /* build_path_to_root works only when we have a valid tcon */
2526 full_path = cifs_build_path_to_root(cifs_sb);
2527 if (full_path == NULL) {
2528 rc = -ENOMEM;
2529 goto mount_fail_check;
2530 }
2531 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002532 if (rc != -EREMOTE) {
Igor Mammedove4cce942009-02-10 14:10:26 +03002533 kfree(full_path);
2534 goto mount_fail_check;
2535 }
2536 kfree(full_path);
2537 }
2538
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002539 /* get referral if needed */
2540 if (rc == -EREMOTE) {
Steve Frenchd036f502009-04-03 03:12:08 +00002541#ifdef CONFIG_CIFS_DFS_UPCALL
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002542 if (referral_walks_count > MAX_NESTED_LINKS) {
2543 /*
2544 * BB: when we implement proper loop detection,
2545 * we will remove this check. But now we need it
2546 * to prevent an indefinite loop if 'DFS tree' is
2547 * misconfigured (i.e. has loops).
2548 */
2549 rc = -ELOOP;
2550 goto mount_fail_check;
2551 }
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002552 /* convert forward to back slashes in prepath here if needed */
2553 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2554 convert_delimiter(cifs_sb->prepath,
2555 CIFS_DIR_SEP(cifs_sb));
2556 full_path = build_unc_path_to_root(volume_info, cifs_sb);
2557 if (IS_ERR(full_path)) {
2558 rc = PTR_ERR(full_path);
2559 goto mount_fail_check;
2560 }
2561
2562 cFYI(1, ("Getting referral for: %s", full_path));
2563 rc = get_dfs_path(xid, pSesInfo , full_path + 1,
2564 cifs_sb->local_nls, &num_referrals, &referrals,
2565 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
2566 if (!rc && num_referrals > 0) {
2567 char *fake_devname = NULL;
2568
2569 if (mount_data != mount_data_global)
2570 kfree(mount_data);
2571 mount_data = cifs_compose_mount_options(
2572 cifs_sb->mountdata, full_path + 1,
2573 referrals, &fake_devname);
2574 kfree(fake_devname);
2575 free_dfs_info_array(referrals, num_referrals);
2576
2577 if (tcon)
2578 cifs_put_tcon(tcon);
2579 else if (pSesInfo)
2580 cifs_put_smb_ses(pSesInfo);
2581
2582 cleanup_volume_info(&volume_info);
2583 FreeXid(xid);
2584 kfree(full_path);
Igor Mammedov5c2503a2009-04-21 19:31:05 +04002585 referral_walks_count++;
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002586 goto try_mount_again;
2587 }
Steve Frenchd036f502009-04-03 03:12:08 +00002588#else /* No DFS support, return error on mount */
2589 rc = -EOPNOTSUPP;
2590#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002591 }
2592
2593mount_fail_check:
2594 /* on error free sesinfo and tcon struct if needed */
2595 if (rc) {
2596 if (mount_data != mount_data_global)
2597 kfree(mount_data);
2598 /* If find_unc succeeded then rc == 0 so we can not end */
2599 /* up accidently freeing someone elses tcon struct */
2600 if (tcon)
2601 cifs_put_tcon(tcon);
2602 else if (pSesInfo)
2603 cifs_put_smb_ses(pSesInfo);
2604 else
2605 cifs_put_tcp_session(srvTcp);
2606 goto out;
2607 }
2608
Jeff Layton7586b762008-12-01 18:41:49 -05002609 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 (in which case it is not needed anymore) but when new sesion is created
2611 the password ptr is put in the new session structure (in which case the
2612 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002613out:
2614 /* zero out password before freeing */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002615 cleanup_volume_info(&volume_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 FreeXid(xid);
2617 return rc;
2618}
2619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620int
2621CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2622 const char *tree, struct cifsTconInfo *tcon,
2623 const struct nls_table *nls_codepage)
2624{
2625 struct smb_hdr *smb_buffer;
2626 struct smb_hdr *smb_buffer_response;
2627 TCONX_REQ *pSMB;
2628 TCONX_RSP *pSMBr;
2629 unsigned char *bcc_ptr;
2630 int rc = 0;
Jeff Laytoncc20c032009-04-30 07:16:21 -04002631 int length, bytes_left;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 __u16 count;
2633
2634 if (ses == NULL)
2635 return -EIO;
2636
2637 smb_buffer = cifs_buf_get();
2638 if (smb_buffer == NULL) {
2639 return -ENOMEM;
2640 }
2641 smb_buffer_response = smb_buffer;
2642
2643 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2644 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07002645
2646 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 smb_buffer->Uid = ses->Suid;
2648 pSMB = (TCONX_REQ *) smb_buffer;
2649 pSMBr = (TCONX_RSP *) smb_buffer_response;
2650
2651 pSMB->AndXCommand = 0xFF;
2652 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002654 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08002655 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00002656 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08002657 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00002658 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08002659 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00002660 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08002661 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
2662 specified as required (when that support is added to
2663 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00002664 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08002665 by Samba (not sure whether other servers allow
2666 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00002667#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00002668 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05002669 (ses->server->secType == LANMAN))
2670 calc_lanman_hash(tcon->password, ses->server->cryptKey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05002671 ses->server->secMode &
2672 SECMODE_PW_ENCRYPT ? true : false,
2673 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00002674 else
2675#endif /* CIFS_WEAK_PW_HASH */
Jeff Layton00e485b2008-12-05 20:41:21 -05002676 SMBNTencrypt(tcon->password, ses->server->cryptKey,
Steve Frencheeac8042006-01-13 21:34:58 -08002677 bcc_ptr);
2678
Steve French7c7b25b2006-06-01 19:20:10 +00002679 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002680 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00002681 /* must align unicode strings */
2682 *bcc_ptr = 0; /* null byte password */
2683 bcc_ptr++;
2684 }
Steve Frencheeac8042006-01-13 21:34:58 -08002685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Steve French50c2f752007-07-13 00:33:32 +00002687 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00002688 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2690
2691 if (ses->capabilities & CAP_STATUS32) {
2692 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2693 }
2694 if (ses->capabilities & CAP_DFS) {
2695 smb_buffer->Flags2 |= SMBFLG2_DFS;
2696 }
2697 if (ses->capabilities & CAP_UNICODE) {
2698 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2699 length =
Steve French50c2f752007-07-13 00:33:32 +00002700 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
2701 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00002702 (/* server len*/ + 256 /* share len */), nls_codepage);
2703 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 bcc_ptr += 2; /* skip trailing null */
2705 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 strcpy(bcc_ptr, tree);
2707 bcc_ptr += strlen(tree) + 1;
2708 }
2709 strcpy(bcc_ptr, "?????");
2710 bcc_ptr += strlen("?????");
2711 bcc_ptr += 1;
2712 count = bcc_ptr - &pSMB->Password[0];
2713 pSMB->hdr.smb_buf_length += count;
2714 pSMB->ByteCount = cpu_to_le16(count);
2715
Steve French133672e2007-11-13 22:41:37 +00002716 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
2717 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 /* above now done in SendReceive */
2720 if ((rc == 0) && (tcon != NULL)) {
Steve French0e0d2cf2009-05-01 05:27:32 +00002721 bool is_unicode;
2722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00002724 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 tcon->tid = smb_buffer_response->Tid;
2726 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04002727 bytes_left = BCC(smb_buffer_response);
2728 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00002729 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
2730 is_unicode = true;
2731 else
2732 is_unicode = false;
2733
Jeff Laytoncc20c032009-04-30 07:16:21 -04002734
Steve French50c2f752007-07-13 00:33:32 +00002735 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00002736 if (length == 3) {
2737 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
2738 (bcc_ptr[2] == 'C')) {
2739 cFYI(1, ("IPC connection"));
2740 tcon->ipc = 1;
2741 }
2742 } else if (length == 2) {
2743 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
2744 /* the most common case */
2745 cFYI(1, ("disk share connection"));
2746 }
2747 }
Steve French50c2f752007-07-13 00:33:32 +00002748 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04002749 bytes_left -= (length + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
Jeff Laytoncc20c032009-04-30 07:16:21 -04002751
2752 /* mostly informational -- no need to fail on error here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002753 tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00002754 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04002755 nls_codepage);
2756
2757 cFYI(1, ("nativeFileSystem=%s", tcon->nativeFileSystem));
2758
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002759 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00002760 (smb_buffer_response->WordCount == 7))
2761 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00002762 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2763 else
2764 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2766 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002767 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 ses->ipc_tid = smb_buffer_response->Tid;
2769 }
2770
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002771 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return rc;
2773}
2774
2775int
2776cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2777{
2778 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002779 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Jeff Laytonf1987b42008-11-15 11:12:47 -05002781 if (cifs_sb->tcon)
2782 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00002783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00002785 tmp = cifs_sb->prepath;
2786 cifs_sb->prepathlen = 0;
2787 cifs_sb->prepath = NULL;
2788 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Steve French88e7d702008-01-03 17:37:09 +00002790 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002791}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00002794 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795{
2796 int rc = 0;
Steve Frenchad009ac2005-04-28 22:41:05 -07002797 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002798 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
2800 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002801 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002803 if (rc == -EAGAIN) {
2804 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00002806 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 rc = -EHOSTDOWN;
2808 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002809 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002811 if (server->tcpStatus != CifsExiting)
2812 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 else
2814 rc = -EHOSTDOWN;
2815 spin_unlock(&GlobalMid_Lock);
2816
2817 }
Steve Frenchad009ac2005-04-28 22:41:05 -07002818 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 }
Steve French26b994f2008-08-06 05:11:33 +00002820
2821 if (rc)
2822 goto ss_err_exit;
2823
2824 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002825 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00002826 if (linuxExtEnabled == 0)
2827 pSesInfo->capabilities &= (~CAP_UNIX);
Steve French20418ac2009-04-30 16:13:32 +00002828
Steve French26b994f2008-08-06 05:11:33 +00002829 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04002830 server->secMode, server->capabilities, server->timeAdj));
2831
Steve French20418ac2009-04-30 16:13:32 +00002832 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
Steve French26b994f2008-08-06 05:11:33 +00002833 if (rc) {
2834 cERROR(1, ("Send error in SessSetup = %d", rc));
2835 } else {
2836 cFYI(1, ("CIFS Session Established successfully"));
Steve French20418ac2009-04-30 16:13:32 +00002837 spin_lock(&GlobalMid_Lock);
2838 pSesInfo->status = CifsGood;
2839 pSesInfo->need_reconnect = false;
2840 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00002841 }
2842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843ss_err_exit:
2844 return rc;
2845}
2846