2005-04-17 02:20:36 +04:00
/*
* fs / cifs / connect . c
*
2009-04-30 21:45:10 +04:00
* Copyright ( C ) International Business Machines Corp . , 2002 , 2009
2005-04-17 02:20:36 +04:00
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See
* the GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
2007-07-10 05:16:18 +04:00
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2005-04-17 02:20:36 +04:00
*/
# include <linux/fs.h>
# include <linux/net.h>
# include <linux/string.h>
# include <linux/list.h>
# include <linux/wait.h>
# include <linux/pagemap.h>
# include <linux/ctype.h>
# include <linux/utsname.h>
# include <linux/mempool.h>
2005-04-29 09:41:07 +04:00
# include <linux/delay.h>
2005-08-18 20:37:34 +04:00
# include <linux/completion.h>
2007-04-03 23:16:43 +04:00
# include <linux/kthread.h>
2005-10-10 21:57:19 +04:00
# include <linux/pagevec.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2009-04-21 19:31:05 +04:00
# include <linux/namei.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/processor.h>
2009-01-31 00:24:41 +03:00
# include <net/ipv6.h>
2005-04-17 02:20:36 +04:00
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_unicode.h"
# include "cifs_debug.h"
# include "cifs_fs_sb.h"
# include "ntlmssp.h"
# include "nterr.h"
# include "rfc1002pdu.h"
2005-11-11 02:33:38 +03:00
# include "cn_cifs.h"
2005-04-17 02:20:36 +04:00
# define CIFS_PORT 445
# define RFC1001_PORT 139
extern void SMBNTencrypt ( unsigned char * passwd , unsigned char * c8 ,
unsigned char * p24 ) ;
extern mempool_t * cifs_req_poolp ;
struct smb_vol {
char * username ;
char * password ;
char * domainname ;
char * UNC ;
char * UNCip ;
2008-05-15 20:44:38 +04:00
char * in6_addr ; /* ipv6 address as human readable form of in6_addr */
2005-04-17 02:20:36 +04:00
char * iocharset ; /* local code page for mapping to and from Unicode */
char source_rfc1001_name [ 16 ] ; /* netbios name of client */
2005-08-23 08:38:31 +04:00
char target_rfc1001_name [ 16 ] ; /* netbios name of server for Win9x/ME */
2005-04-17 02:20:36 +04:00
uid_t linux_uid ;
gid_t linux_gid ;
mode_t file_mode ;
mode_t dir_mode ;
2006-06-23 06:33:48 +04:00
unsigned secFlg ;
2008-04-29 04:06:05 +04:00
bool rw : 1 ;
bool retry : 1 ;
bool intr : 1 ;
bool setuids : 1 ;
bool override_uid : 1 ;
bool override_gid : 1 ;
2008-05-13 02:23:49 +04:00
bool dynperm : 1 ;
2008-04-29 04:06:05 +04:00
bool noperm : 1 ;
bool no_psx_acl : 1 ; /* set if posix acl support should be disabled */
bool cifs_acl : 1 ;
bool no_xattr : 1 ; /* set if xattr (EA) support should be disabled*/
bool server_ino : 1 ; /* use inode numbers from server ie UniqueId */
bool direct_io : 1 ;
2008-05-15 20:44:38 +04:00
bool remap : 1 ; /* set to remap seven reserved chars in filenames */
bool posix_paths : 1 ; /* unset to not ask for posix pathnames. */
2008-04-29 04:06:05 +04:00
bool no_linux_ext : 1 ;
bool sfu_emul : 1 ;
2008-05-15 20:44:38 +04:00
bool nullauth : 1 ; /* attempt to authenticate with null user */
bool nocase : 1 ; /* request case insensitive filenames */
bool nobrl : 1 ; /* disable sending byte range locks to srv */
2008-12-02 20:24:33 +03:00
bool mand_lock : 1 ; /* send mandatory not posix byte range lock reqs */
2008-05-15 20:44:38 +04:00
bool seal : 1 ; /* request transport encryption on share */
2008-10-23 08:42:37 +04:00
bool nodfs : 1 ; /* Do not request DFS, even if available */
bool local_lease : 1 ; /* check leases only on local system, not remote */
2008-10-29 03:47:57 +03:00
bool noblocksnd : 1 ;
bool noautotune : 1 ;
2009-02-23 18:21:59 +03:00
bool nostrictsync : 1 ; /* do not force expensive SMBflush on every sync */
2005-04-17 02:20:36 +04:00
unsigned int rsize ;
unsigned int wsize ;
unsigned int sockopt ;
unsigned short int port ;
2007-07-10 05:16:18 +04:00
char * prepath ;
2005-04-17 02:20:36 +04:00
} ;
2008-12-02 02:42:15 +03:00
static int ipv4_connect ( struct TCP_Server_Info * server ) ;
2008-12-02 02:42:33 +03:00
static int ipv6_connect ( struct TCP_Server_Info * server ) ;
2005-04-17 02:20:36 +04:00
2008-12-02 02:42:33 +03:00
/*
* cifs tcp session reconnection
*
* mark tcp session as reconnecting so temporarily locked
* mark all smb sessions as reconnecting for tcp session
* reconnect tcp session
* wake up waiters on reconnection ? - ( not needed currently )
*/
2006-09-28 23:43:08 +04:00
static int
2005-04-17 02:20:36 +04:00
cifs_reconnect ( struct TCP_Server_Info * server )
{
int rc = 0 ;
2008-11-15 19:12:47 +03:00
struct list_head * tmp , * tmp2 ;
2005-04-17 02:20:36 +04:00
struct cifsSesInfo * ses ;
struct cifsTconInfo * tcon ;
2007-07-10 05:16:18 +04:00
struct mid_q_entry * mid_entry ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
2008-10-16 22:46:39 +04:00
if ( server - > tcpStatus = = CifsExiting ) {
2007-07-10 05:16:18 +04:00
/* the demux thread will exit normally
2005-04-17 02:20:36 +04:00
next time through the loop */
spin_unlock ( & GlobalMid_Lock ) ;
return rc ;
} else
server - > tcpStatus = CifsNeedReconnect ;
spin_unlock ( & GlobalMid_Lock ) ;
server - > maxBuf = 0 ;
2005-04-29 09:41:09 +04:00
cFYI ( 1 , ( " Reconnecting tcp session " ) ) ;
2005-04-17 02:20:36 +04:00
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
2008-11-14 21:53:46 +03:00
read_lock ( & cifs_tcp_ses_lock ) ;
list_for_each ( tmp , & server - > smb_ses_list ) {
ses = list_entry ( tmp , struct cifsSesInfo , smb_ses_list ) ;
ses - > need_reconnect = true ;
ses - > ipc_tid = 0 ;
2008-11-15 19:12:47 +03:00
list_for_each ( tmp2 , & ses - > tcon_list ) {
tcon = list_entry ( tmp2 , struct cifsTconInfo , tcon_list ) ;
2008-11-13 22:45:32 +03:00
tcon - > need_reconnect = true ;
2005-04-17 02:20:36 +04:00
}
}
2008-11-15 19:12:47 +03:00
read_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
/* do not want to be sending data on a socket we are freeing */
2008-12-01 15:09:36 +03:00
mutex_lock ( & server - > srv_mutex ) ;
2007-07-10 05:16:18 +04:00
if ( server - > ssocket ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " State: 0x%x Flags: 0x%lx " , server - > ssocket - > state ,
2005-04-17 02:20:36 +04:00
server - > ssocket - > flags ) ) ;
2007-11-13 05:10:39 +03:00
kernel_sock_shutdown ( server - > ssocket , SHUT_WR ) ;
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " Post shutdown state: 0x%x Flags: 0x%lx " ,
2007-06-28 02:41:32 +04:00
server - > ssocket - > state ,
2005-04-17 02:20:36 +04:00
server - > ssocket - > flags ) ) ;
sock_release ( server - > ssocket ) ;
server - > ssocket = NULL ;
}
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct
mid_q_entry ,
qhead ) ;
2008-08-09 01:10:16 +04:00
if ( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) {
2005-04-29 09:41:08 +04:00
/* Mark other intransit requests as needing
retry so we do not immediately mark the
session bad again ( ie after we reconnect
below ) as they timeout too */
2008-08-09 01:10:16 +04:00
mid_entry - > midState = MID_RETRY_NEEDED ;
2005-04-17 02:20:36 +04:00
}
}
spin_unlock ( & GlobalMid_Lock ) ;
2008-12-01 15:09:36 +03:00
mutex_unlock ( & server - > srv_mutex ) ;
2005-04-17 02:20:36 +04:00
2008-10-16 22:46:39 +04:00
while ( ( server - > tcpStatus ! = CifsExiting ) & &
( server - > tcpStatus ! = CifsGood ) ) {
2006-08-01 02:46:20 +04:00
try_to_freeze ( ) ;
2008-12-02 02:42:15 +03:00
if ( server - > addr . sockAddr6 . sin6_family = = AF_INET6 )
2008-12-02 02:42:33 +03:00
rc = ipv6_connect ( server ) ;
2008-12-02 02:42:15 +03:00
else
rc = ipv4_connect ( server ) ;
2007-07-10 05:16:18 +04:00
if ( rc ) {
cFYI ( 1 , ( " reconnect error %d " , rc ) ) ;
2005-04-29 09:41:11 +04:00
msleep ( 3000 ) ;
2005-04-17 02:20:36 +04:00
} else {
atomic_inc ( & tcpSesReconnectCount ) ;
spin_lock ( & GlobalMid_Lock ) ;
2008-10-16 22:46:39 +04:00
if ( server - > tcpStatus ! = CifsExiting )
2005-04-17 02:20:36 +04:00
server - > tcpStatus = CifsGood ;
2005-04-29 09:41:05 +04:00
server - > sequence_number = 0 ;
2007-07-10 05:16:18 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2005-04-17 02:20:36 +04:00
/* atomic_set(&server->inFlight,0);*/
wake_up ( & server - > response_q ) ;
}
}
return rc ;
}
2007-07-10 05:16:18 +04:00
/*
2005-04-29 09:41:09 +04:00
return codes :
0 not a transact2 , or all data present
> 0 transact2 with that much data missing
- EINVAL = invalid transact2
*/
2007-07-10 05:16:18 +04:00
static int check2ndT2 ( struct smb_hdr * pSMB , unsigned int maxBufSize )
2005-04-29 09:41:09 +04:00
{
2007-07-10 05:16:18 +04:00
struct smb_t2_rsp * pSMBt ;
int total_data_size ;
2005-04-29 09:41:09 +04:00
int data_in_this_rsp ;
int remaining ;
2007-07-10 05:16:18 +04:00
if ( pSMB - > Command ! = SMB_COM_TRANSACTION2 )
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-10 05:16:18 +04:00
/* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */
if ( pSMB - > WordCount ! = 10 ) { /* coalesce_t2 depends on this */
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " invalid transact2 word count " ) ) ;
2005-04-29 09:41:09 +04:00
return - EINVAL ;
}
pSMBt = ( struct smb_t2_rsp * ) pSMB ;
total_data_size = le16_to_cpu ( pSMBt - > t2_rsp . TotalDataCount ) ;
data_in_this_rsp = le16_to_cpu ( pSMBt - > t2_rsp . DataCount ) ;
remaining = total_data_size - data_in_this_rsp ;
2007-07-10 05:16:18 +04:00
if ( remaining = = 0 )
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-10 05:16:18 +04:00
else if ( remaining < 0 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " total data %d smaller than data in frame %d " ,
2005-04-29 09:41:09 +04:00
total_data_size , data_in_this_rsp ) ) ;
return - EINVAL ;
} else {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " missing %d bytes from transact2, check next response " ,
2005-04-29 09:41:09 +04:00
remaining ) ) ;
2007-07-10 05:16:18 +04:00
if ( total_data_size > maxBufSize ) {
cERROR ( 1 , ( " TotalDataSize %d is over maximum buffer %d " ,
total_data_size , maxBufSize ) ) ;
return - EINVAL ;
2005-04-29 09:41:09 +04:00
}
return remaining ;
}
}
2007-07-10 05:16:18 +04:00
static int coalesce_t2 ( struct smb_hdr * psecond , struct smb_hdr * pTargetSMB )
2005-04-29 09:41:09 +04:00
{
struct smb_t2_rsp * pSMB2 = ( struct smb_t2_rsp * ) psecond ;
struct smb_t2_rsp * pSMBt = ( struct smb_t2_rsp * ) pTargetSMB ;
int total_data_size ;
int total_in_buf ;
int remaining ;
int total_in_buf2 ;
2007-07-10 05:16:18 +04:00
char * data_area_of_target ;
char * data_area_of_buf2 ;
2005-04-29 09:41:09 +04:00
__u16 byte_count ;
total_data_size = le16_to_cpu ( pSMBt - > t2_rsp . TotalDataCount ) ;
2007-07-10 05:16:18 +04:00
if ( total_data_size ! = le16_to_cpu ( pSMB2 - > t2_rsp . TotalDataCount ) ) {
2007-07-17 21:34:02 +04:00
cFYI ( 1 , ( " total data size of primary and secondary t2 differ " ) ) ;
2005-04-29 09:41:09 +04:00
}
total_in_buf = le16_to_cpu ( pSMBt - > t2_rsp . DataCount ) ;
remaining = total_data_size - total_in_buf ;
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( remaining < 0 )
2005-04-29 09:41:09 +04:00
return - EINVAL ;
2007-07-10 05:16:18 +04:00
if ( remaining = = 0 ) /* nothing to do, ignore */
2005-04-29 09:41:09 +04:00
return 0 ;
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:09 +04:00
total_in_buf2 = le16_to_cpu ( pSMB2 - > t2_rsp . DataCount ) ;
2007-07-10 05:16:18 +04:00
if ( remaining < total_in_buf2 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " transact2 2nd response contains too much data " ) ) ;
2005-04-29 09:41:09 +04:00
}
/* find end of first SMB data area */
2007-07-10 05:16:18 +04:00
data_area_of_target = ( char * ) & pSMBt - > hdr . Protocol +
2005-04-29 09:41:09 +04:00
le16_to_cpu ( pSMBt - > t2_rsp . DataOffset ) ;
/* validate target area */
data_area_of_buf2 = ( char * ) & pSMB2 - > hdr . Protocol +
2007-07-10 05:16:18 +04:00
le16_to_cpu ( pSMB2 - > t2_rsp . DataOffset ) ;
2005-04-29 09:41:09 +04:00
data_area_of_target + = total_in_buf ;
/* copy second buffer into end of first buffer */
2007-07-10 05:16:18 +04:00
memcpy ( data_area_of_target , data_area_of_buf2 , total_in_buf2 ) ;
2005-04-29 09:41:09 +04:00
total_in_buf + = total_in_buf2 ;
pSMBt - > t2_rsp . DataCount = cpu_to_le16 ( total_in_buf ) ;
byte_count = le16_to_cpu ( BCC_LE ( pTargetSMB ) ) ;
byte_count + = total_in_buf2 ;
BCC_LE ( pTargetSMB ) = cpu_to_le16 ( byte_count ) ;
2005-09-23 03:32:06 +04:00
byte_count = pTargetSMB - > smb_buf_length ;
2005-04-29 09:41:09 +04:00
byte_count + = total_in_buf2 ;
/* BB also add check that we are not beyond maximum buffer size */
2007-07-13 04:33:32 +04:00
2005-09-23 03:32:06 +04:00
pTargetSMB - > smb_buf_length = byte_count ;
2005-04-29 09:41:09 +04:00
2007-07-10 05:16:18 +04:00
if ( remaining = = total_in_buf2 ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " found the last secondary response " ) ) ;
2005-04-29 09:41:09 +04:00
return 0 ; /* we are done */
} else /* more responses to go */
return 1 ;
}
2005-04-17 02:20:36 +04:00
static int
cifs_demultiplex_thread ( struct TCP_Server_Info * server )
{
int length ;
unsigned int pdu_length , total_read ;
struct smb_hdr * smb_buffer = NULL ;
2005-04-29 09:41:07 +04:00
struct smb_hdr * bigbuf = NULL ;
struct smb_hdr * smallbuf = NULL ;
2005-04-17 02:20:36 +04:00
struct msghdr smb_msg ;
struct kvec iov ;
struct socket * csocket = server - > ssocket ;
struct list_head * tmp ;
struct cifsSesInfo * ses ;
struct task_struct * task_to_wake = NULL ;
struct mid_q_entry * mid_entry ;
2005-09-23 03:32:06 +04:00
char temp ;
2008-04-29 04:06:05 +04:00
bool isLargeBuf = false ;
bool isMultiRsp ;
2005-04-29 09:41:09 +04:00
int reconnect ;
2005-04-17 02:20:36 +04:00
current - > flags | = PF_MEMALLOC ;
2007-10-19 10:40:40 +04:00
cFYI ( 1 , ( " Demultiplex PID: %d " , task_pid_nr ( current ) ) ) ;
2008-08-02 16:00:48 +04:00
length = atomic_inc_return ( & tcpSesAllocCount ) ;
if ( length > 1 )
2007-08-31 02:09:15 +04:00
mempool_resize ( cifs_req_poolp , length + cifs_min_rcv ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2008-10-16 22:46:39 +04:00
while ( server - > tcpStatus ! = CifsExiting ) {
2005-08-31 07:10:14 +04:00
if ( try_to_freeze ( ) )
continue ;
2005-04-29 09:41:07 +04:00
if ( bigbuf = = NULL ) {
bigbuf = cifs_buf_get ( ) ;
2006-06-14 01:31:39 +04:00
if ( ! bigbuf ) {
cERROR ( 1 , ( " No memory for large SMB response " ) ) ;
2005-04-29 09:41:07 +04:00
msleep ( 3000 ) ;
/* retry will check if exiting */
continue ;
}
2006-06-14 01:31:39 +04:00
} else if ( isLargeBuf ) {
/* we are reusing a dirty large buf, clear its start */
2007-08-31 02:09:15 +04:00
memset ( bigbuf , 0 , sizeof ( struct smb_hdr ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-04-29 09:41:07 +04:00
if ( smallbuf = = NULL ) {
smallbuf = cifs_small_buf_get ( ) ;
2006-06-14 01:31:39 +04:00
if ( ! smallbuf ) {
cERROR ( 1 , ( " No memory for SMB response " ) ) ;
2005-04-29 09:41:07 +04:00
msleep ( 1000 ) ;
/* retry will check if exiting */
continue ;
}
/* beginning of smb buffer is cleared in our buf_get */
} else /* if existing small buf clear beginning */
2007-08-31 02:09:15 +04:00
memset ( smallbuf , 0 , sizeof ( struct smb_hdr ) ) ;
2005-04-29 09:41:07 +04:00
2008-04-29 04:06:05 +04:00
isLargeBuf = false ;
isMultiRsp = false ;
2005-04-29 09:41:07 +04:00
smb_buffer = smallbuf ;
2005-04-17 02:20:36 +04:00
iov . iov_base = smb_buffer ;
iov . iov_len = 4 ;
smb_msg . msg_control = NULL ;
smb_msg . msg_controllen = 0 ;
2007-08-31 01:13:31 +04:00
pdu_length = 4 ; /* enough to get RFC1001 header */
incomplete_rcv :
2005-04-17 02:20:36 +04:00
length =
kernel_recvmsg ( csocket , & smb_msg ,
2007-08-31 01:13:31 +04:00
& iov , 1 , pdu_length , 0 /* BB other flags? */ ) ;
2005-04-17 02:20:36 +04:00
2008-10-16 22:46:39 +04:00
if ( server - > tcpStatus = = CifsExiting ) {
2005-04-17 02:20:36 +04:00
break ;
} else if ( server - > tcpStatus = = CifsNeedReconnect ) {
2006-06-14 01:31:39 +04:00
cFYI ( 1 , ( " Reconnect after server stopped responding " ) ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
2006-06-14 01:31:39 +04:00
cFYI ( 1 , ( " call to reconnect done " ) ) ;
2005-04-17 02:20:36 +04:00
csocket = server - > ssocket ;
continue ;
} else if ( ( length = = - ERESTARTSYS ) | | ( length = = - EAGAIN ) ) {
2005-04-29 09:41:07 +04:00
msleep ( 1 ) ; /* minimum sleep to prevent looping
2005-04-17 02:20:36 +04:00
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
2008-11-03 23:46:21 +03:00
if ( pdu_length < 4 ) {
iov . iov_base = ( 4 - pdu_length ) +
( char * ) smb_buffer ;
iov . iov_len = pdu_length ;
smb_msg . msg_control = NULL ;
smb_msg . msg_controllen = 0 ;
2007-10-17 22:01:11 +04:00
goto incomplete_rcv ;
2008-11-03 23:46:21 +03:00
} else
2007-10-17 22:01:11 +04:00
continue ;
2005-04-17 02:20:36 +04:00
} else if ( length < = 0 ) {
2006-06-14 01:31:39 +04:00
if ( server - > tcpStatus = = CifsNew ) {
cFYI ( 1 , ( " tcp session abend after SMBnegprot " ) ) ;
2005-04-29 09:41:08 +04:00
/* some servers kill the TCP session rather than
returning an SMB negprot error , in which
case reconnecting here is not going to help ,
and so simply return error to mount */
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-14 01:31:39 +04:00
if ( ! try_to_freeze ( ) & & ( length = = - EINTR ) ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " cifsd thread killed " ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Reconnect after unexpected peek error %d " ,
2005-04-29 09:41:10 +04:00
length ) ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
wake_up ( & server - > response_q ) ;
continue ;
2007-11-20 05:24:08 +03:00
} else if ( length < pdu_length ) {
cFYI ( 1 , ( " requested %d bytes but only got %d bytes " ,
pdu_length , length ) ) ;
2007-08-31 01:13:31 +04:00
pdu_length - = length ;
msleep ( 1 ) ;
goto incomplete_rcv ;
2005-04-29 09:41:09 +04:00
}
2005-04-17 02:20:36 +04:00
2005-09-23 03:32:06 +04:00
/* The right amount was read from socket - 4 bytes */
/* so we can now interpret the length field */
2005-04-29 09:41:09 +04:00
2005-09-23 03:32:06 +04:00
/* the first byte big endian of the length field,
is actually not part of the length but the type
with the most common , zero , as regular data */
temp = * ( ( char * ) smb_buffer ) ;
2005-04-29 09:41:09 +04:00
2007-07-10 05:16:18 +04:00
/* Note that FC 1001 length is big endian on the wire,
2005-09-23 03:32:06 +04:00
but we convert it here so it is always manipulated
as host byte order */
2008-07-24 04:45:58 +04:00
pdu_length = be32_to_cpu ( ( __force __be32 ) smb_buffer - > smb_buf_length ) ;
2005-09-23 03:32:06 +04:00
smb_buffer - > smb_buf_length = pdu_length ;
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " rfc1002 length 0x%x " , pdu_length + 4 ) ) ;
2005-04-29 09:41:09 +04:00
2005-09-23 03:32:06 +04:00
if ( temp = = ( char ) RFC1002_SESSION_KEEP_ALIVE ) {
2007-07-10 05:16:18 +04:00
continue ;
2005-09-23 03:32:06 +04:00
} else if ( temp = = ( char ) RFC1002_POSITIVE_SESSION_RESPONSE ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Good RFC 1002 session rsp " ) ) ;
2005-04-29 09:41:09 +04:00
continue ;
2005-09-23 03:32:06 +04:00
} else if ( temp = = ( char ) RFC1002_NEGATIVE_SESSION_RESPONSE ) {
2007-07-10 05:16:18 +04:00
/* we get this from Windows 98 instead of
2005-04-29 09:41:09 +04:00
an error on SMB negprot response */
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " Negative RFC1002 Session Response Error 0x%x) " ,
2005-09-23 03:32:06 +04:00
pdu_length ) ) ;
2007-07-10 05:16:18 +04:00
if ( server - > tcpStatus = = CifsNew ) {
/* if nack on negprot (rather than
2005-04-29 09:41:09 +04:00
ret of smb negprot error ) reconnecting
not going to help , ret error to mount */
break ;
} else {
/* give server a second to
clean up before reconnect attempt */
msleep ( 1000 ) ;
/* always try 445 first on reconnect
since we get NACK on some if we ever
2007-07-10 05:16:18 +04:00
connected to port 139 ( the NACK is
2005-04-29 09:41:09 +04:00
since we do not begin with RFC1001
session initialize frame ) */
2007-07-10 05:16:18 +04:00
server - > addr . sockAddr . sin_port =
2005-04-29 09:41:09 +04:00
htons ( CIFS_PORT ) ;
2005-04-17 02:20:36 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
2005-04-29 09:41:09 +04:00
wake_up ( & server - > response_q ) ;
2005-04-17 02:20:36 +04:00
continue ;
2005-04-29 09:41:09 +04:00
}
2005-09-23 03:32:06 +04:00
} else if ( temp ! = ( char ) 0 ) {
2007-07-10 05:16:18 +04:00
cERROR ( 1 , ( " Unknown RFC 1002 frame " ) ) ;
2005-09-23 03:32:06 +04:00
cifs_dump_mem ( " Received Data: " , ( char * ) smb_buffer ,
length ) ;
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
continue ;
2005-04-29 09:41:09 +04:00
}
/* else we have an SMB response */
2007-07-10 05:16:18 +04:00
if ( ( pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4 ) | |
2007-08-31 02:09:15 +04:00
( pdu_length < sizeof ( struct smb_hdr ) - 1 - 4 ) ) {
2005-04-29 09:41:09 +04:00
cERROR ( 1 , ( " Invalid size SMB length %d pdu_length %d " ,
2005-04-29 09:41:09 +04:00
length , pdu_length + 4 ) ) ;
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
wake_up ( & server - > response_q ) ;
continue ;
2007-07-10 05:16:18 +04:00
}
2005-04-29 09:41:09 +04:00
/* else length ok */
reconnect = 0 ;
2007-07-10 05:16:18 +04:00
if ( pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4 ) {
2008-04-29 04:06:05 +04:00
isLargeBuf = true ;
2005-04-29 09:41:09 +04:00
memcpy ( bigbuf , smallbuf , 4 ) ;
smb_buffer = bigbuf ;
}
length = 0 ;
iov . iov_base = 4 + ( char * ) smb_buffer ;
iov . iov_len = pdu_length ;
2007-07-10 05:16:18 +04:00
for ( total_read = 0 ; total_read < pdu_length ;
2005-04-29 09:41:09 +04:00
total_read + = length ) {
length = kernel_recvmsg ( csocket , & smb_msg , & iov , 1 ,
pdu_length - total_read , 0 ) ;
2008-10-16 22:46:39 +04:00
if ( ( server - > tcpStatus = = CifsExiting ) | |
2005-04-29 09:41:09 +04:00
( length = = - EINTR ) ) {
/* then will exit */
reconnect = 2 ;
break ;
} else if ( server - > tcpStatus = = CifsNeedReconnect ) {
2005-04-29 09:41:09 +04:00
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
2007-07-10 05:16:18 +04:00
/* Reconnect wakes up rspns q */
2005-04-29 09:41:09 +04:00
/* Now we will reread sock */
reconnect = 1 ;
break ;
2007-07-10 05:16:18 +04:00
} else if ( ( length = = - ERESTARTSYS ) | |
2005-04-29 09:41:09 +04:00
( length = = - EAGAIN ) ) {
msleep ( 1 ) ; /* minimum sleep to prevent looping,
2007-07-10 05:16:18 +04:00
allowing socket to clear and app
2005-04-29 09:41:09 +04:00
threads to set tcpStatus
CifsNeedReconnect if server hung */
2007-10-17 22:01:11 +04:00
length = 0 ;
2005-04-29 09:41:09 +04:00
continue ;
2005-04-29 09:41:09 +04:00
} else if ( length < = 0 ) {
2007-07-10 05:16:18 +04:00
cERROR ( 1 , ( " Received no data, expecting %d " ,
2005-04-29 09:41:09 +04:00
pdu_length - total_read ) ) ;
cifs_reconnect ( server ) ;
csocket = server - > ssocket ;
reconnect = 1 ;
break ;
2005-04-29 09:41:09 +04:00
}
2005-04-29 09:41:09 +04:00
}
2007-07-10 05:16:18 +04:00
if ( reconnect = = 2 )
2005-04-29 09:41:09 +04:00
break ;
2007-07-10 05:16:18 +04:00
else if ( reconnect = = 1 )
2005-04-29 09:41:09 +04:00
continue ;
2005-04-17 02:20:36 +04:00
2005-04-29 09:41:09 +04:00
length + = 4 ; /* account for rfc1002 hdr */
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:08 +04:00
2005-04-29 09:41:09 +04:00
dump_smb ( smb_buffer , length ) ;
2006-02-24 09:15:11 +03:00
if ( checkSMB ( smb_buffer , smb_buffer - > Mid , total_read + 4 ) ) {
2005-10-11 01:21:15 +04:00
cifs_dump_mem ( " Bad SMB: " , smb_buffer , 48 ) ;
2005-04-29 09:41:09 +04:00
continue ;
}
2005-04-17 02:20:36 +04:00
2005-04-29 09:41:09 +04:00
task_to_wake = NULL ;
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct mid_q_entry , qhead ) ;
2007-07-13 04:33:32 +04:00
if ( ( mid_entry - > mid = = smb_buffer - > Mid ) & &
2005-04-29 09:41:09 +04:00
( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) & &
( mid_entry - > command = = smb_buffer - > Command ) ) {
2007-07-10 05:16:18 +04:00
if ( check2ndT2 ( smb_buffer , server - > maxBuf ) > 0 ) {
2005-04-29 09:41:09 +04:00
/* We have a multipart transact2 resp */
2008-04-29 04:06:05 +04:00
isMultiRsp = true ;
2007-07-10 05:16:18 +04:00
if ( mid_entry - > resp_buf ) {
2005-04-29 09:41:09 +04:00
/* merge response - fix up 1st*/
2007-07-13 04:33:32 +04:00
if ( coalesce_t2 ( smb_buffer ,
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf ) ) {
2008-04-29 04:06:05 +04:00
mid_entry - > multiRsp =
true ;
2005-04-29 09:41:09 +04:00
break ;
} else {
/* all parts received */
2008-04-29 04:06:05 +04:00
mid_entry - > multiEnd =
true ;
2007-07-13 04:33:32 +04:00
goto multi_t2_fnd ;
2005-04-29 09:41:09 +04:00
}
} else {
2007-07-10 05:16:18 +04:00
if ( ! isLargeBuf ) {
2005-04-29 09:41:09 +04:00
cERROR ( 1 , ( " 1st trans2 resp needs bigbuf " ) ) ;
/* BB maybe we can fix this up, switch
2007-07-13 04:33:32 +04:00
to already allocated large buffer ? */
2005-04-29 09:41:09 +04:00
} else {
2005-04-29 09:41:10 +04:00
/* Have first buffer */
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf =
smb_buffer ;
2008-04-29 04:06:05 +04:00
mid_entry - > largeBuf =
true ;
2005-04-29 09:41:09 +04:00
bigbuf = NULL ;
}
}
break ;
2007-07-13 04:33:32 +04:00
}
2005-04-29 09:41:09 +04:00
mid_entry - > resp_buf = smb_buffer ;
2008-04-29 04:06:05 +04:00
mid_entry - > largeBuf = isLargeBuf ;
2005-04-29 09:41:09 +04:00
multi_t2_fnd :
task_to_wake = mid_entry - > tsk ;
mid_entry - > midState = MID_RESPONSE_RECEIVED ;
2005-10-12 06:58:06 +04:00
# ifdef CONFIG_CIFS_STATS2
mid_entry - > when_received = jiffies ;
# endif
2006-07-15 02:37:11 +04:00
/* so we do not time out requests to server
which is still responding ( since server could
be busy but not dead ) */
server - > lstrp = jiffies ;
2005-04-29 09:41:09 +04:00
break ;
2005-04-29 09:41:09 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-04-29 09:41:09 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
if ( task_to_wake ) {
2005-04-29 09:41:10 +04:00
/* Was previous buf put in mpx struct for multi-rsp? */
2007-07-10 05:16:18 +04:00
if ( ! isMultiRsp ) {
2005-04-29 09:41:10 +04:00
/* smb buffer will be freed by user thread */
2007-08-31 02:09:15 +04:00
if ( isLargeBuf )
2005-04-29 09:41:10 +04:00
bigbuf = NULL ;
2007-08-31 02:09:15 +04:00
else
2005-04-29 09:41:10 +04:00
smallbuf = NULL ;
}
2005-04-29 09:41:09 +04:00
wake_up_process ( task_to_wake ) ;
2008-04-29 04:06:05 +04:00
} else if ( ! is_valid_oplock_break ( smb_buffer , server ) & &
! isMultiRsp ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " No task to wake, unknown frame received! "
" NumMids %d " , midCount . counter ) ) ;
cifs_dump_mem ( " Received Data is: " , ( char * ) smb_buffer ,
2005-09-23 03:32:06 +04:00
sizeof ( struct smb_hdr ) ) ;
2006-06-01 02:40:51 +04:00
# ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail ( smb_buffer ) ;
cifs_dump_mids ( server ) ;
# endif /* CIFS_DEBUG2 */
2007-07-13 04:33:32 +04:00
2005-04-29 09:41:09 +04:00
}
} /* end while !EXITING */
2008-11-14 21:44:38 +03:00
/* take it off the list, if it's not already */
write_lock ( & cifs_tcp_ses_lock ) ;
list_del_init ( & server - > tcp_ses_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
server - > tcpStatus = CifsExiting ;
2008-05-11 19:53:33 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2008-06-11 01:21:56 +04:00
wake_up_all ( & server - > response_q ) ;
2008-05-11 19:53:33 +04:00
2005-04-29 09:41:11 +04:00
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
2008-05-11 19:53:33 +04:00
spin_lock ( & GlobalMid_Lock ) ;
2007-07-10 05:16:18 +04:00
if ( atomic_read ( & server - > inFlight ) > = cifs_max_pending )
2005-04-29 09:41:11 +04:00
atomic_set ( & server - > inFlight , cifs_max_pending - 1 ) ;
/* We do not want to set the max_pending too low or we
could end up with the counter going negative */
2005-04-17 02:20:36 +04:00
spin_unlock ( & GlobalMid_Lock ) ;
2007-07-13 04:33:32 +04:00
/* Although there should not be any requests blocked on
2005-04-17 02:20:36 +04:00
this queue it can not hurt to be paranoid and try to wake up requests
2005-04-29 09:41:08 +04:00
that may haven been blocked when more than 50 at time were on the wire
2005-04-17 02:20:36 +04:00
to the same server - they now will see the session is in exit state
and get out of SendReceive . */
wake_up_all ( & server - > request_q ) ;
/* give those requests time to exit */
2005-04-29 09:41:07 +04:00
msleep ( 125 ) ;
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( server - > ssocket ) {
2005-04-17 02:20:36 +04:00
sock_release ( csocket ) ;
server - > ssocket = NULL ;
}
2005-04-29 09:41:07 +04:00
/* buffer usuallly freed in free_mid - need to free it here on exit */
2007-10-03 20:41:24 +04:00
cifs_buf_release ( bigbuf ) ;
if ( smallbuf ) /* no sense logging a debug message if NULL */
2005-04-29 09:41:07 +04:00
cifs_small_buf_release ( smallbuf ) ;
2005-04-17 02:20:36 +04:00
2008-11-14 21:53:46 +03:00
/*
* BB : we shouldn ' t have to do any of this . It shouldn ' t be
* possible to exit from the thread with active SMB sessions
*/
read_lock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
if ( list_empty ( & server - > pending_mid_q ) ) {
2005-04-29 09:41:08 +04:00
/* loop through server session structures attached to this and
mark them dead */
2008-11-14 21:53:46 +03:00
list_for_each ( tmp , & server - > smb_ses_list ) {
ses = list_entry ( tmp , struct cifsSesInfo ,
smb_ses_list ) ;
ses - > status = CifsExiting ;
ses - > server = NULL ;
2005-04-17 02:20:36 +04:00
}
2008-11-14 21:53:46 +03:00
read_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-04-29 09:41:11 +04:00
/* although we can not zero the server struct pointer yet,
since there are active requests which may depnd on them ,
mark the corresponding SMB sessions as exiting too */
2008-11-14 21:53:46 +03:00
list_for_each ( tmp , & server - > smb_ses_list ) {
2005-04-29 09:41:11 +04:00
ses = list_entry ( tmp , struct cifsSesInfo ,
2008-11-14 21:53:46 +03:00
smb_ses_list ) ;
ses - > status = CifsExiting ;
2005-04-29 09:41:11 +04:00
}
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
list_for_each ( tmp , & server - > pending_mid_q ) {
mid_entry = list_entry ( tmp , struct mid_q_entry , qhead ) ;
if ( mid_entry - > midState = = MID_REQUEST_SUBMITTED ) {
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Clearing Mid 0x%x - waking up " ,
mid_entry - > mid ) ) ;
2005-04-17 02:20:36 +04:00
task_to_wake = mid_entry - > tsk ;
2007-08-31 02:09:15 +04:00
if ( task_to_wake )
2005-04-17 02:20:36 +04:00
wake_up_process ( task_to_wake ) ;
}
}
spin_unlock ( & GlobalMid_Lock ) ;
2008-11-14 21:53:46 +03:00
read_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
/* 1/8th of sec is more than enough time for them to exit */
2005-04-29 09:41:07 +04:00
msleep ( 125 ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-18 20:37:34 +04:00
if ( ! list_empty ( & server - > pending_mid_q ) ) {
2007-07-13 04:33:32 +04:00
/* mpx threads have not exited yet give them
2005-04-17 02:20:36 +04:00
at least the smb send timeout time for long ops */
2005-04-29 09:41:11 +04:00
/* due to delays on oplock break requests, we need
to wait at least 45 seconds before giving up
on a request getting a response and going ahead
and killing cifsd */
2005-04-17 02:20:36 +04:00
cFYI ( 1 , ( " Wait for exit from demultiplex thread " ) ) ;
2005-04-29 09:41:11 +04:00
msleep ( 46000 ) ;
2005-04-17 02:20:36 +04:00
/* if threads still have not exited they are probably never
coming home not much else we can do but free the memory */
}
2005-04-29 09:41:11 +04:00
/* last chance to mark ses pointers invalid
if there are any pointing to this ( e . g
2007-07-13 04:33:32 +04:00
if a crazy root user tried to kill cifsd
2005-04-29 09:41:11 +04:00
kernel thread explicitly this might happen ) */
2008-11-14 21:53:46 +03:00
/* BB: This shouldn't be necessary, see above */
read_lock ( & cifs_tcp_ses_lock ) ;
list_for_each ( tmp , & server - > smb_ses_list ) {
ses = list_entry ( tmp , struct cifsSesInfo , smb_ses_list ) ;
ses - > server = NULL ;
2005-04-29 09:41:11 +04:00
}
2008-11-14 21:53:46 +03:00
read_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-29 09:41:11 +04:00
2007-11-17 01:22:06 +03:00
kfree ( server - > hostname ) ;
2008-10-22 21:57:07 +04:00
task_to_wake = xchg ( & server - > tsk , NULL ) ;
2005-04-29 09:41:11 +04:00
kfree ( server ) ;
2008-08-02 16:00:48 +04:00
length = atomic_dec_return ( & tcpSesAllocCount ) ;
2007-08-31 02:09:15 +04:00
if ( length > 0 )
mempool_resize ( cifs_req_poolp , length + cifs_min_rcv ,
GFP_KERNEL ) ;
2007-07-13 04:33:32 +04:00
2008-10-22 21:57:07 +04:00
/* if server->tsk was NULL then wait for a signal before exiting */
if ( ! task_to_wake ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( ! signal_pending ( current ) ) {
schedule ( ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
}
set_current_state ( TASK_RUNNING ) ;
}
2008-12-01 15:09:35 +03:00
module_put_and_exit ( 0 ) ;
2005-04-17 02:20:36 +04:00
}
2007-11-17 01:22:06 +03:00
/* extract the host portion of the UNC string */
static char *
extract_hostname ( const char * unc )
{
const char * src ;
char * dst , * delim ;
unsigned int len ;
/* skip double chars at beginning of string */
/* BB: check validity of these bytes? */
src = unc + 2 ;
/* delimiter between hostname and sharename is always '\\' now */
delim = strchr ( src , ' \\ ' ) ;
if ( ! delim )
return ERR_PTR ( - EINVAL ) ;
len = delim - src ;
dst = kmalloc ( ( len + 1 ) , GFP_KERNEL ) ;
if ( dst = = NULL )
return ERR_PTR ( - ENOMEM ) ;
memcpy ( dst , src , len ) ;
dst [ len ] = ' \0 ' ;
return dst ;
}
2005-04-17 02:20:36 +04:00
static int
2007-07-13 04:33:32 +04:00
cifs_parse_mount_options ( char * options , const char * devname ,
struct smb_vol * vol )
2005-04-17 02:20:36 +04:00
{
char * value ;
char * data ;
unsigned int temp_len , i , j ;
char separator [ 2 ] ;
separator [ 0 ] = ' , ' ;
2007-07-13 04:33:32 +04:00
separator [ 1 ] = 0 ;
2005-04-17 02:20:36 +04:00
2006-10-13 19:09:29 +04:00
if ( Local_System_Name [ 0 ] ! = 0 )
2007-07-13 04:33:32 +04:00
memcpy ( vol - > source_rfc1001_name , Local_System_Name , 15 ) ;
2006-09-28 23:43:08 +04:00
else {
2006-10-13 19:09:29 +04:00
char * nodename = utsname ( ) - > nodename ;
2007-07-13 04:33:32 +04:00
int n = strnlen ( nodename , 15 ) ;
memset ( vol - > source_rfc1001_name , 0x20 , 15 ) ;
for ( i = 0 ; i < n ; i + + ) {
2006-09-28 23:43:08 +04:00
/* does not have to be perfect mapping since field is
informational , only used for servers that do not support
port 445 and it can be overridden at mount time */
2006-10-13 19:09:29 +04:00
vol - > source_rfc1001_name [ i ] = toupper ( nodename [ i ] ) ;
2006-09-28 23:43:08 +04:00
}
2005-04-17 02:20:36 +04:00
}
vol - > source_rfc1001_name [ 15 ] = 0 ;
2005-08-23 08:38:31 +04:00
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol - > target_rfc1001_name [ 0 ] = 0 ;
2008-11-14 02:38:47 +03:00
vol - > linux_uid = current_uid ( ) ; /* use current_euid() instead? */
vol - > linux_gid = current_gid ( ) ;
2005-04-17 02:20:36 +04:00
vol - > dir_mode = S_IRWXUGO ;
/* 2767 perms indicate mandatory locking support */
2007-11-01 21:03:01 +03:00
vol - > file_mode = ( S_IRWXUGO | S_ISGID ) & ( ~ S_IXGRP ) ;
2005-04-17 02:20:36 +04:00
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
2008-04-29 04:06:05 +04:00
vol - > rw = true ;
2005-06-23 04:26:35 +04:00
/* default is always to request posix paths. */
vol - > posix_paths = 1 ;
2005-04-17 02:20:36 +04:00
if ( ! options )
return 1 ;
2007-07-13 04:33:32 +04:00
if ( strncmp ( options , " sep= " , 4 ) = = 0 ) {
2007-07-10 05:16:18 +04:00
if ( options [ 4 ] ! = 0 ) {
2005-04-17 02:20:36 +04:00
separator [ 0 ] = options [ 4 ] ;
options + = 5 ;
} else {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " Null separator not allowed " ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
while ( ( data = strsep ( & options , separator ) ) ! = NULL ) {
if ( ! * data )
continue ;
if ( ( value = strchr ( data , ' = ' ) ) ! = NULL )
* value + + = ' \0 ' ;
2007-07-13 04:33:32 +04:00
/* Have to parse this before we parse for "user" */
if ( strnicmp ( data , " user_xattr " , 10 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_xattr = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " nouser_xattr " , 12 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_xattr = 1 ;
} else if ( strnicmp ( data , " user " , 4 ) = = 0 ) {
2006-10-31 00:46:13 +03:00
if ( ! value ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING
" CIFS: invalid or missing username \n " ) ;
return 1 ; /* needs_arg; */
2007-07-10 05:16:18 +04:00
} else if ( ! * value ) {
2006-10-31 00:46:13 +03:00
/* null user, ie anonymous, authentication */
vol - > nullauth = 1 ;
2005-04-17 02:20:36 +04:00
}
if ( strnlen ( value , 200 ) < 200 ) {
vol - > username = value ;
} else {
printk ( KERN_WARNING " CIFS: username too long \n " ) ;
return 1 ;
}
} else if ( strnicmp ( data , " pass " , 4 ) = = 0 ) {
if ( ! value ) {
vol - > password = NULL ;
continue ;
2007-07-10 05:16:18 +04:00
} else if ( value [ 0 ] = = 0 ) {
2005-04-17 02:20:36 +04:00
/* check if string begins with double comma
since that would mean the password really
does start with a comma , and would not
indicate an empty string */
2007-07-10 05:16:18 +04:00
if ( value [ 1 ] ! = separator [ 0 ] ) {
2005-04-17 02:20:36 +04:00
vol - > password = NULL ;
continue ;
}
}
temp_len = strlen ( value ) ;
/* removed password length check, NTLM passwords
can be arbitrarily long */
2007-07-13 04:33:32 +04:00
/* if comma in password, the string will be
2005-04-17 02:20:36 +04:00
prematurely null terminated . Commas in password are
specified across the cifs mount interface by a double
comma ie , , and a comma used as in other cases ie ' , '
as a parameter delimiter / separator is single and due
to the strsep above is temporarily zeroed . */
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
2007-07-13 04:33:32 +04:00
if ( ( value [ temp_len ] = = 0 ) & &
2005-04-29 09:41:08 +04:00
( value [ temp_len + 1 ] = = separator [ 0 ] ) ) {
2005-04-17 02:20:36 +04:00
/* reinsert comma */
value [ temp_len ] = separator [ 0 ] ;
2007-07-13 04:33:32 +04:00
temp_len + = 2 ; /* move after second comma */
while ( value [ temp_len ] ! = 0 ) {
2005-04-17 02:20:36 +04:00
if ( value [ temp_len ] = = separator [ 0 ] ) {
2007-07-13 04:33:32 +04:00
if ( value [ temp_len + 1 ] = =
2005-04-29 09:41:08 +04:00
separator [ 0 ] ) {
/* skip second comma */
temp_len + + ;
2007-07-13 04:33:32 +04:00
} else {
2005-04-17 02:20:36 +04:00
/* single comma indicating start
of next parm */
break ;
}
}
temp_len + + ;
}
2007-07-10 05:16:18 +04:00
if ( value [ temp_len ] = = 0 ) {
2005-04-17 02:20:36 +04:00
options = NULL ;
} else {
value [ temp_len ] = 0 ;
/* point option to start of next parm */
options = value + temp_len + 1 ;
}
2007-07-13 04:33:32 +04:00
/* go from value to value + temp_len condensing
2005-04-17 02:20:36 +04:00
double commas to singles . Note that this ends up
allocating a few bytes too many , which is ok */
2005-09-07 02:18:35 +04:00
vol - > password = kzalloc ( temp_len , GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( vol - > password = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: no memory "
" for password \n " ) ;
2005-04-29 09:41:08 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
for ( i = 0 , j = 0 ; i < temp_len ; i + + , j + + ) {
2005-04-17 02:20:36 +04:00
vol - > password [ j ] = value [ i ] ;
2007-07-10 05:16:18 +04:00
if ( value [ i ] = = separator [ 0 ]
2005-04-29 09:41:08 +04:00
& & value [ i + 1 ] = = separator [ 0 ] ) {
2005-04-17 02:20:36 +04:00
/* skip second comma */
i + + ;
}
}
vol - > password [ j ] = 0 ;
} else {
2005-09-07 02:18:35 +04:00
vol - > password = kzalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( vol - > password = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: no memory "
" for password \n " ) ;
2005-04-29 09:41:08 +04:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
strcpy ( vol - > password , value ) ;
}
} else if ( strnicmp ( data , " ip " , 2 ) = = 0 ) {
if ( ! value | | ! * value ) {
vol - > UNCip = NULL ;
} else if ( strnlen ( value , 35 ) < 35 ) {
vol - > UNCip = value ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: ip address "
" too long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sec " , 3 ) = = 0 ) {
if ( ! value | | ! * value ) {
cERROR ( 1 , ( " no security value specified " ) ) ;
continue ;
} else if ( strnicmp ( value , " krb5i " , 5 ) = = 0 ) {
vol - > secFlg | = CIFSSEC_MAY_KRB5 |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " krb5p " , 5 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
/* vol->secFlg |= CIFSSEC_MUST_SEAL |
CIFSSEC_MAY_KRB5 ; */
cERROR ( 1 , ( " Krb5 cifs privacy not supported " ) ) ;
2005-12-02 09:32:42 +03:00
return 1 ;
} else if ( strnicmp ( value , " krb5 " , 4 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_KRB5 ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmv2i " , 7 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmv2 " , 6 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlmi " , 5 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLM |
2006-06-23 06:33:48 +04:00
CIFSSEC_MUST_SIGN ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " ntlm " , 4 ) = = 0 ) {
/* ntlm is default so can be turned off too */
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLM ;
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " nontlm " , 6 ) = = 0 ) {
2006-06-23 06:33:48 +04:00
/* BB is there a better way to do this? */
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MAY_NTLMV2 ;
2006-06-23 06:33:48 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if ( strnicmp ( value , " lanman " , 6 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
vol - > secFlg | = CIFSSEC_MAY_LANMAN ;
2006-06-23 06:33:48 +04:00
# endif
2005-12-02 09:32:42 +03:00
} else if ( strnicmp ( value , " none " , 4 ) = = 0 ) {
2006-06-23 06:33:48 +04:00
vol - > nullauth = 1 ;
2007-07-13 04:33:32 +04:00
} else {
cERROR ( 1 , ( " bad security option: %s " , value ) ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
} else if ( ( strnicmp ( data , " unc " , 3 ) = = 0 )
| | ( strnicmp ( data , " target " , 6 ) = = 0 )
| | ( strnicmp ( data , " path " , 4 ) = = 0 ) ) {
if ( ! value | | ! * value ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: invalid path to "
" network resource \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ; /* needs_arg; */
}
if ( ( temp_len = strnlen ( value , 300 ) ) < 300 ) {
2007-07-13 04:33:32 +04:00
vol - > UNC = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-05-01 00:13:06 +04:00
if ( vol - > UNC = = NULL )
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > UNC , value ) ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( vol - > UNC , " // " , 2 ) = = 0 ) {
vol - > UNC [ 0 ] = ' \\ ' ;
vol - > UNC [ 1 ] = ' \\ ' ;
2007-07-13 04:33:32 +04:00
} else if ( strncmp ( vol - > UNC , " \\ \\ " , 2 ) ! = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING
2007-07-13 04:33:32 +04:00
" CIFS: UNC Path does not begin "
" with // or \\ \\ \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else {
printk ( KERN_WARNING " CIFS: UNC name too long \n " ) ;
return 1 ;
}
} else if ( ( strnicmp ( data , " domain " , 3 ) = = 0 )
| | ( strnicmp ( data , " workgroup " , 5 ) = = 0 ) ) {
if ( ! value | | ! * value ) {
printk ( KERN_WARNING " CIFS: invalid domain name \n " ) ;
return 1 ; /* needs_arg; */
}
/* BB are there cases in which a comma can be valid in
a domain name and need special handling ? */
2006-06-01 02:40:51 +04:00
if ( strnlen ( value , 256 ) < 256 ) {
2005-04-17 02:20:36 +04:00
vol - > domainname = value ;
cFYI ( 1 , ( " Domain name set " ) ) ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: domain name too "
" long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " prefixpath " , 10 ) = = 0 ) {
if ( ! value | | ! * value ) {
printk ( KERN_WARNING
" CIFS: invalid path prefix \n " ) ;
return 1 ; /* needs_argument */
}
if ( ( temp_len = strnlen ( value , 1024 ) ) < 1024 ) {
2007-05-01 00:13:06 +04:00
if ( value [ 0 ] ! = ' / ' )
2006-09-21 11:02:52 +04:00
temp_len + + ; /* missing leading slash */
2007-07-13 04:33:32 +04:00
vol - > prepath = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
if ( vol - > prepath = = NULL )
return 1 ;
2007-05-01 00:13:06 +04:00
if ( value [ 0 ] ! = ' / ' ) {
2006-09-21 11:02:52 +04:00
vol - > prepath [ 0 ] = ' / ' ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > prepath + 1 , value ) ;
2006-09-21 11:02:52 +04:00
} else
2007-07-13 04:33:32 +04:00
strcpy ( vol - > prepath , value ) ;
cFYI ( 1 , ( " prefix path %s " , vol - > prepath ) ) ;
} else {
printk ( KERN_WARNING " CIFS: prefix too long \n " ) ;
return 1 ;
}
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " iocharset " , 9 ) = = 0 ) {
if ( ! value | | ! * value ) {
2007-07-17 21:34:02 +04:00
printk ( KERN_WARNING " CIFS: invalid iocharset "
" specified \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ; /* needs_arg; */
}
if ( strnlen ( value , 65 ) < 65 ) {
2007-07-13 04:33:32 +04:00
if ( strnicmp ( value , " default " , 7 ) )
2005-04-17 02:20:36 +04:00
vol - > iocharset = value ;
2007-07-13 04:33:32 +04:00
/* if iocharset not set then load_nls_default
is used by caller */
cFYI ( 1 , ( " iocharset set to %s " , value ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-17 21:34:02 +04:00
printk ( KERN_WARNING " CIFS: iocharset name "
" too long. \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else if ( strnicmp ( data , " uid " , 3 ) = = 0 ) {
if ( value & & * value ) {
vol - > linux_uid =
simple_strtoul ( value , & value , 0 ) ;
2007-05-01 00:13:06 +04:00
vol - > override_uid = 1 ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " gid " , 3 ) = = 0 ) {
if ( value & & * value ) {
vol - > linux_gid =
simple_strtoul ( value , & value , 0 ) ;
2007-05-01 00:13:06 +04:00
vol - > override_gid = 1 ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " file_mode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > file_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " dir_mode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > dir_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " dirmode " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > dir_mode =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " port " , 4 ) = = 0 ) {
if ( value & & * value ) {
vol - > port =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " rsize " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > rsize =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " wsize " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > wsize =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " sockopt " , 5 ) = = 0 ) {
if ( value & & * value ) {
vol - > sockopt =
simple_strtoul ( value , & value , 0 ) ;
}
} else if ( strnicmp ( data , " netbiosname " , 4 ) = = 0 ) {
if ( ! value | | ! * value | | ( * value = = ' ' ) ) {
2007-07-17 21:34:02 +04:00
cFYI ( 1 , ( " invalid (empty) netbiosname " ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-07-13 04:33:32 +04:00
memset ( vol - > source_rfc1001_name , 0x20 , 15 ) ;
for ( i = 0 ; i < 15 ; i + + ) {
/* BB are there cases in which a comma can be
2005-04-17 02:20:36 +04:00
valid in this workstation netbios name ( and need
special handling ) ? */
/* We do not uppercase netbiosname for user */
2007-07-13 04:33:32 +04:00
if ( value [ i ] = = 0 )
2005-04-17 02:20:36 +04:00
break ;
2007-07-13 04:33:32 +04:00
else
vol - > source_rfc1001_name [ i ] =
value [ i ] ;
2005-04-17 02:20:36 +04:00
}
/* The string has 16th byte zero still from
set at top of the function */
2007-07-13 04:33:32 +04:00
if ( ( i = = 15 ) & & ( value [ i ] ! = 0 ) )
printk ( KERN_WARNING " CIFS: netbiosname "
" longer than 15 truncated. \n " ) ;
2005-08-23 08:38:31 +04:00
}
} else if ( strnicmp ( data , " servern " , 7 ) = = 0 ) {
/* servernetbiosname specified override *SMBSERVER */
if ( ! value | | ! * value | | ( * value = = ' ' ) ) {
2007-06-28 02:41:32 +04:00
cFYI ( 1 , ( " empty server netbiosname specified " ) ) ;
2005-08-23 08:38:31 +04:00
} else {
/* last byte, type, is 0x20 for servr type */
2007-07-13 04:33:32 +04:00
memset ( vol - > target_rfc1001_name , 0x20 , 16 ) ;
2005-08-23 08:38:31 +04:00
2007-07-13 04:33:32 +04:00
for ( i = 0 ; i < 15 ; i + + ) {
2005-08-23 08:38:31 +04:00
/* BB are there cases in which a comma can be
2007-07-13 04:33:32 +04:00
valid in this workstation netbios name
( and need special handling ) ? */
2005-08-23 08:38:31 +04:00
2007-07-13 04:33:32 +04:00
/* user or mount helper must uppercase
the netbiosname */
if ( value [ i ] = = 0 )
2005-08-23 08:38:31 +04:00
break ;
else
2007-07-13 04:33:32 +04:00
vol - > target_rfc1001_name [ i ] =
value [ i ] ;
2005-08-23 08:38:31 +04:00
}
/* The string has 16th byte zero still from
set at top of the function */
2007-07-13 04:33:32 +04:00
if ( ( i = = 15 ) & & ( value [ i ] ! = 0 ) )
printk ( KERN_WARNING " CIFS: server net "
" biosname longer than 15 truncated. \n " ) ;
2005-04-17 02:20:36 +04:00
}
} else if ( strnicmp ( data , " credentials " , 4 ) = = 0 ) {
/* ignore */
} else if ( strnicmp ( data , " version " , 3 ) = = 0 ) {
/* ignore */
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " guest " , 5 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
/* ignore */
} else if ( strnicmp ( data , " rw " , 2 ) = = 0 ) {
2008-04-29 04:06:05 +04:00
vol - > rw = true ;
2008-10-29 03:47:57 +03:00
} else if ( strnicmp ( data , " noblocksend " , 11 ) = = 0 ) {
vol - > noblocksnd = 1 ;
} else if ( strnicmp ( data , " noautotune " , 10 ) = = 0 ) {
vol - > noautotune = 1 ;
2005-04-17 02:20:36 +04:00
} else if ( ( strnicmp ( data , " suid " , 4 ) = = 0 ) | |
( strnicmp ( data , " nosuid " , 6 ) = = 0 ) | |
( strnicmp ( data , " exec " , 4 ) = = 0 ) | |
( strnicmp ( data , " noexec " , 6 ) = = 0 ) | |
( strnicmp ( data , " nodev " , 5 ) = = 0 ) | |
( strnicmp ( data , " noauto " , 6 ) = = 0 ) | |
( strnicmp ( data , " dev " , 3 ) = = 0 ) ) {
/* The mount tool or mount.cifs helper (if present)
2007-07-13 04:33:32 +04:00
uses these opts to set flags , and the flags are read
by the kernel vfs layer before we get here ( ie
before read super ) so there is no point trying to
parse these options again and set anything and it
is ok to just ignore them */
2005-04-17 02:20:36 +04:00
continue ;
} else if ( strnicmp ( data , " ro " , 2 ) = = 0 ) {
2008-04-29 04:06:05 +04:00
vol - > rw = false ;
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " hard " , 4 ) = = 0 ) {
vol - > retry = 1 ;
} else if ( strnicmp ( data , " soft " , 4 ) = = 0 ) {
vol - > retry = 0 ;
} else if ( strnicmp ( data , " perm " , 4 ) = = 0 ) {
vol - > noperm = 0 ;
} else if ( strnicmp ( data , " noperm " , 6 ) = = 0 ) {
vol - > noperm = 1 ;
2005-04-29 09:41:05 +04:00
} else if ( strnicmp ( data , " mapchars " , 8 ) = = 0 ) {
vol - > remap = 1 ;
} else if ( strnicmp ( data , " nomapchars " , 10 ) = = 0 ) {
vol - > remap = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sfu " , 3 ) = = 0 ) {
vol - > sfu_emul = 1 ;
} else if ( strnicmp ( data , " nosfu " , 5 ) = = 0 ) {
vol - > sfu_emul = 0 ;
2008-10-16 22:35:21 +04:00
} else if ( strnicmp ( data , " nodfs " , 5 ) = = 0 ) {
vol - > nodfs = 1 ;
2005-06-23 04:26:35 +04:00
} else if ( strnicmp ( data , " posixpaths " , 10 ) = = 0 ) {
vol - > posix_paths = 1 ;
} else if ( strnicmp ( data , " noposixpaths " , 12 ) = = 0 ) {
vol - > posix_paths = 0 ;
2007-07-19 03:21:09 +04:00
} else if ( strnicmp ( data , " nounix " , 6 ) = = 0 ) {
vol - > no_linux_ext = 1 ;
} else if ( strnicmp ( data , " nolinux " , 7 ) = = 0 ) {
vol - > no_linux_ext = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( ( strnicmp ( data , " nocase " , 6 ) = = 0 ) | |
2005-08-23 08:38:31 +04:00
( strnicmp ( data , " ignorecase " , 10 ) = = 0 ) ) {
2007-07-13 04:33:32 +04:00
vol - > nocase = 1 ;
2005-08-19 07:49:57 +04:00
} else if ( strnicmp ( data , " brl " , 3 ) = = 0 ) {
vol - > nobrl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( ( strnicmp ( data , " nobrl " , 5 ) = = 0 ) | |
2005-08-31 07:58:07 +04:00
( strnicmp ( data , " nolock " , 6 ) = = 0 ) ) {
2005-08-19 07:49:57 +04:00
vol - > nobrl = 1 ;
2005-08-19 22:04:29 +04:00
/* turn off mandatory locking in mode
if remote locking is turned off since the
local vfs will do advisory */
2007-07-13 04:33:32 +04:00
if ( vol - > file_mode = =
( S_IALLUGO & ~ ( S_ISUID | S_IXGRP ) ) )
2005-08-19 22:04:29 +04:00
vol - > file_mode = S_IALLUGO ;
2008-12-02 20:24:33 +03:00
} else if ( strnicmp ( data , " forcemandatorylock " , 9 ) = = 0 ) {
/* will take the shorter form "forcemand" as well */
/* This mount option will force use of mandatory
( DOS / Windows style ) byte range locks , instead of
using posix advisory byte range locks , even if the
Unix extensions are available and posix locks would
be supported otherwise . If Unix extensions are not
negotiated this has no effect since mandatory locks
would be used ( mandatory locks is all that those
those servers support ) */
vol - > mand_lock = 1 ;
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " setuids " , 7 ) = = 0 ) {
vol - > setuids = 1 ;
} else if ( strnicmp ( data , " nosetuids " , 9 ) = = 0 ) {
vol - > setuids = 0 ;
2008-05-13 02:23:49 +04:00
} else if ( strnicmp ( data , " dynperm " , 7 ) = = 0 ) {
vol - > dynperm = true ;
} else if ( strnicmp ( data , " nodynperm " , 9 ) = = 0 ) {
vol - > dynperm = false ;
2005-04-17 02:20:36 +04:00
} else if ( strnicmp ( data , " nohard " , 6 ) = = 0 ) {
vol - > retry = 0 ;
} else if ( strnicmp ( data , " nosoft " , 6 ) = = 0 ) {
vol - > retry = 1 ;
} else if ( strnicmp ( data , " nointr " , 6 ) = = 0 ) {
vol - > intr = 0 ;
} else if ( strnicmp ( data , " intr " , 4 ) = = 0 ) {
vol - > intr = 1 ;
2009-02-23 18:21:59 +03:00
} else if ( strnicmp ( data , " nostrictsync " , 12 ) = = 0 ) {
vol - > nostrictsync = 1 ;
} else if ( strnicmp ( data , " strictsync " , 10 ) = = 0 ) {
vol - > nostrictsync = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " serverino " , 7 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > server_ino = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " noserverino " , 9 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > server_ino = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " cifsacl " , 7 ) = = 0 ) {
2006-01-13 02:44:21 +03:00
vol - > cifs_acl = 1 ;
} else if ( strnicmp ( data , " nocifsacl " , 9 ) = = 0 ) {
vol - > cifs_acl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " acl " , 3 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_psx_acl = 0 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " noacl " , 5 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > no_psx_acl = 1 ;
2008-10-23 08:42:37 +04:00
# ifdef CONFIG_CIFS_EXPERIMENTAL
} else if ( strnicmp ( data , " locallease " , 6 ) = = 0 ) {
vol - > local_lease = 1 ;
# endif
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " sign " , 4 ) = = 0 ) {
2006-06-27 10:28:30 +04:00
vol - > secFlg | = CIFSSEC_MUST_SIGN ;
2008-05-15 20:44:38 +04:00
} else if ( strnicmp ( data , " seal " , 4 ) = = 0 ) {
/* we do not do the following in secFlags because seal
is a per tree connection ( mount ) not a per socket
or per - smb connection option in the protocol */
/* vol->secFlg |= CIFSSEC_MUST_SEAL; */
vol - > seal = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " direct " , 6 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > direct_io = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " forcedirectio " , 13 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
vol - > direct_io = 1 ;
2007-07-13 04:33:32 +04:00
} else if ( strnicmp ( data , " in6_addr " , 8 ) = = 0 ) {
2005-04-17 02:20:36 +04:00
if ( ! value | | ! * value ) {
vol - > in6_addr = NULL ;
} else if ( strnlen ( value , 49 ) = = 48 ) {
vol - > in6_addr = value ;
} else {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: ip v6 address not "
" 48 characters long \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
} else if ( strnicmp ( data , " noac " , 4 ) = = 0 ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Mount option noac not "
" supported. Instead set "
" /proc/fs/cifs/LookupCacheEnabled to 0 \n " ) ;
2005-04-17 02:20:36 +04:00
} else
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Unknown mount option %s \n " ,
data ) ;
2005-04-17 02:20:36 +04:00
}
if ( vol - > UNC = = NULL ) {
2007-05-01 00:13:06 +04:00
if ( devname = = NULL ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: Missing UNC name for mount "
" target \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
if ( ( temp_len = strnlen ( devname , 300 ) ) < 300 ) {
2007-07-13 04:33:32 +04:00
vol - > UNC = kmalloc ( temp_len + 1 , GFP_KERNEL ) ;
2007-05-01 00:13:06 +04:00
if ( vol - > UNC = = NULL )
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-13 04:33:32 +04:00
strcpy ( vol - > UNC , devname ) ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( vol - > UNC , " // " , 2 ) = = 0 ) {
vol - > UNC [ 0 ] = ' \\ ' ;
vol - > UNC [ 1 ] = ' \\ ' ;
} else if ( strncmp ( vol - > UNC , " \\ \\ " , 2 ) ! = 0 ) {
2007-07-13 04:33:32 +04:00
printk ( KERN_WARNING " CIFS: UNC Path does not "
" begin with // or \\ \\ \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
2008-05-09 00:48:42 +04:00
value = strpbrk ( vol - > UNC + 2 , " / \\ " ) ;
if ( value )
* value = ' \\ ' ;
2005-04-17 02:20:36 +04:00
} else {
printk ( KERN_WARNING " CIFS: UNC name too long \n " ) ;
return 1 ;
}
}
2007-07-10 05:16:18 +04:00
if ( vol - > UNCip = = NULL )
2005-04-17 02:20:36 +04:00
vol - > UNCip = & vol - > UNC [ 2 ] ;
return 0 ;
}
2008-11-14 21:44:38 +03:00
static struct TCP_Server_Info *
2009-01-22 22:43:21 +03:00
cifs_find_tcp_session ( struct sockaddr_storage * addr )
2005-04-17 02:20:36 +04:00
{
struct list_head * tmp ;
2008-11-14 21:44:38 +03:00
struct TCP_Server_Info * server ;
struct sockaddr_in * addr4 = ( struct sockaddr_in * ) addr ;
struct sockaddr_in6 * addr6 = ( struct sockaddr_in6 * ) addr ;
write_lock ( & cifs_tcp_ses_lock ) ;
list_for_each ( tmp , & cifs_tcp_ses_list ) {
server = list_entry ( tmp , struct TCP_Server_Info ,
tcp_ses_list ) ;
/*
* the demux thread can exit on its own while still in CifsNew
* so don ' t accept any sockets in that state . Since the
* tcpStatus never changes back to CifsNew it ' s safe to check
* for this without a lock .
*/
if ( server - > tcpStatus = = CifsNew )
2008-05-09 22:17:21 +04:00
continue ;
2005-04-17 02:20:36 +04:00
2009-01-22 22:43:21 +03:00
if ( addr - > ss_family = = AF_INET & &
2008-11-14 21:44:38 +03:00
( addr4 - > sin_addr . s_addr ! =
server - > addr . sockAddr . sin_addr . s_addr ) )
continue ;
2009-01-22 22:43:21 +03:00
else if ( addr - > ss_family = = AF_INET6 & &
2009-01-31 00:24:41 +03:00
! ipv6_addr_equal ( & server - > addr . sockAddr6 . sin6_addr ,
& addr6 - > sin6_addr ) )
2008-05-09 22:17:21 +04:00
continue ;
2008-11-14 21:44:38 +03:00
+ + server - > srv_count ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2008-11-15 03:07:26 +03:00
cFYI ( 1 , ( " Existing tcp session with server found " ) ) ;
2008-11-14 21:44:38 +03:00
return server ;
2005-04-17 02:20:36 +04:00
}
2008-11-14 21:44:38 +03:00
write_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-05-09 22:17:21 +04:00
2008-11-14 21:53:46 +03:00
static void
2008-11-14 21:44:38 +03:00
cifs_put_tcp_session ( struct TCP_Server_Info * server )
2005-04-17 02:20:36 +04:00
{
2008-11-14 21:44:38 +03:00
struct task_struct * task ;
2008-05-09 22:17:21 +04:00
2008-11-14 21:44:38 +03:00
write_lock ( & cifs_tcp_ses_lock ) ;
if ( - - server - > srv_count > 0 ) {
write_unlock ( & cifs_tcp_ses_lock ) ;
return ;
2005-04-17 02:20:36 +04:00
}
2008-05-09 22:17:21 +04:00
2008-11-14 21:44:38 +03:00
list_del_init ( & server - > tcp_ses_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2008-05-07 02:05:51 +04:00
2008-11-14 21:44:38 +03:00
spin_lock ( & GlobalMid_Lock ) ;
server - > tcpStatus = CifsExiting ;
spin_unlock ( & GlobalMid_Lock ) ;
2008-05-07 02:05:51 +04:00
2008-11-14 21:44:38 +03:00
task = xchg ( & server - > tsk , NULL ) ;
if ( task )
force_sig ( SIGKILL , task ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-02 02:41:46 +03:00
static struct TCP_Server_Info *
cifs_get_tcp_session ( struct smb_vol * volume_info )
{
struct TCP_Server_Info * tcp_ses = NULL ;
2009-01-22 22:43:21 +03:00
struct sockaddr_storage addr ;
2008-12-02 02:41:46 +03:00
struct sockaddr_in * sin_server = ( struct sockaddr_in * ) & addr ;
struct sockaddr_in6 * sin_server6 = ( struct sockaddr_in6 * ) & addr ;
int rc ;
2009-01-22 22:43:21 +03:00
memset ( & addr , 0 , sizeof ( struct sockaddr_storage ) ) ;
2008-12-02 02:41:46 +03:00
if ( volume_info - > UNCip & & volume_info - > UNC ) {
rc = cifs_inet_pton ( AF_INET , volume_info - > UNCip ,
& sin_server - > sin_addr . s_addr ) ;
if ( rc < = 0 ) {
/* not ipv4 address, try ipv6 */
rc = cifs_inet_pton ( AF_INET6 , volume_info - > UNCip ,
& sin_server6 - > sin6_addr . in6_u ) ;
if ( rc > 0 )
2009-01-22 22:43:21 +03:00
addr . ss_family = AF_INET6 ;
2008-12-02 02:41:46 +03:00
} else {
2009-01-22 22:43:21 +03:00
addr . ss_family = AF_INET ;
2008-12-02 02:41:46 +03:00
}
if ( rc < = 0 ) {
/* we failed translating address */
rc = - EINVAL ;
goto out_err ;
}
cFYI ( 1 , ( " UNC: %s ip: %s " , volume_info - > UNC ,
volume_info - > UNCip ) ) ;
} else if ( volume_info - > UNCip ) {
/* BB using ip addr as tcp_ses name to connect to the
DFS root below */
cERROR ( 1 , ( " Connecting to DFS root not implemented yet " ) ) ;
rc = - EINVAL ;
goto out_err ;
} else /* which tcp_sess DFS root would we conect to */ {
cERROR ( 1 ,
( " CIFS mount error: No UNC path (e.g. -o "
" unc=//192.168.1.100/public) specified " ) ) ;
rc = - EINVAL ;
goto out_err ;
}
/* see if we already have a matching tcp_ses */
tcp_ses = cifs_find_tcp_session ( & addr ) ;
if ( tcp_ses )
return tcp_ses ;
tcp_ses = kzalloc ( sizeof ( struct TCP_Server_Info ) , GFP_KERNEL ) ;
if ( ! tcp_ses ) {
rc = - ENOMEM ;
goto out_err ;
}
tcp_ses - > hostname = extract_hostname ( volume_info - > UNC ) ;
if ( IS_ERR ( tcp_ses - > hostname ) ) {
rc = PTR_ERR ( tcp_ses - > hostname ) ;
goto out_err ;
}
tcp_ses - > noblocksnd = volume_info - > noblocksnd ;
tcp_ses - > noautotune = volume_info - > noautotune ;
atomic_set ( & tcp_ses - > inFlight , 0 ) ;
init_waitqueue_head ( & tcp_ses - > response_q ) ;
init_waitqueue_head ( & tcp_ses - > request_q ) ;
INIT_LIST_HEAD ( & tcp_ses - > pending_mid_q ) ;
mutex_init ( & tcp_ses - > srv_mutex ) ;
memcpy ( tcp_ses - > workstation_RFC1001_name ,
volume_info - > source_rfc1001_name , RFC1001_NAME_LEN_WITH_NULL ) ;
memcpy ( tcp_ses - > server_RFC1001_name ,
volume_info - > target_rfc1001_name , RFC1001_NAME_LEN_WITH_NULL ) ;
tcp_ses - > sequence_number = 0 ;
INIT_LIST_HEAD ( & tcp_ses - > tcp_ses_list ) ;
INIT_LIST_HEAD ( & tcp_ses - > smb_ses_list ) ;
/*
* at this point we are the only ones with the pointer
* to the struct since the kernel thread not created yet
* no need to spinlock this init of tcpStatus or srv_count
*/
tcp_ses - > tcpStatus = CifsNew ;
+ + tcp_ses - > srv_count ;
2009-01-22 22:43:21 +03:00
if ( addr . ss_family = = AF_INET6 ) {
2008-12-02 02:41:46 +03:00
cFYI ( 1 , ( " attempting ipv6 connect " ) ) ;
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
memcpy ( & tcp_ses - > addr . sockAddr6 , sin_server6 ,
sizeof ( struct sockaddr_in6 ) ) ;
sin_server6 - > sin6_port = htons ( volume_info - > port ) ;
2008-12-02 02:42:33 +03:00
rc = ipv6_connect ( tcp_ses ) ;
2008-12-02 02:41:46 +03:00
} else {
memcpy ( & tcp_ses - > addr . sockAddr , sin_server ,
sizeof ( struct sockaddr_in ) ) ;
sin_server - > sin_port = htons ( volume_info - > port ) ;
2008-12-02 02:42:15 +03:00
rc = ipv4_connect ( tcp_ses ) ;
2008-12-02 02:41:46 +03:00
}
if ( rc < 0 ) {
cERROR ( 1 , ( " Error connecting to socket. Aborting operation " ) ) ;
goto out_err ;
}
/*
* since we ' re in a cifs function already , we know that
* this will succeed . No need for try_module_get ( ) .
*/
__module_get ( THIS_MODULE ) ;
tcp_ses - > tsk = kthread_run ( ( void * ) ( void * ) cifs_demultiplex_thread ,
tcp_ses , " cifsd " ) ;
if ( IS_ERR ( tcp_ses - > tsk ) ) {
rc = PTR_ERR ( tcp_ses - > tsk ) ;
cERROR ( 1 , ( " error %d create cifsd thread " , rc ) ) ;
module_put ( THIS_MODULE ) ;
goto out_err ;
}
/* thread spawned, put it on the list */
write_lock ( & cifs_tcp_ses_lock ) ;
list_add ( & tcp_ses - > tcp_ses_list , & cifs_tcp_ses_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
return tcp_ses ;
out_err :
if ( tcp_ses ) {
kfree ( tcp_ses - > hostname ) ;
if ( tcp_ses - > ssocket )
sock_release ( tcp_ses - > ssocket ) ;
kfree ( tcp_ses ) ;
}
return ERR_PTR ( rc ) ;
}
2008-11-14 21:53:46 +03:00
static struct cifsSesInfo *
cifs_find_smb_ses ( struct TCP_Server_Info * server , char * username )
2005-04-17 02:20:36 +04:00
{
struct list_head * tmp ;
2008-11-14 21:53:46 +03:00
struct cifsSesInfo * ses ;
2008-05-07 02:05:51 +04:00
2008-11-14 21:53:46 +03:00
write_lock ( & cifs_tcp_ses_lock ) ;
list_for_each ( tmp , & server - > smb_ses_list ) {
ses = list_entry ( tmp , struct cifsSesInfo , smb_ses_list ) ;
if ( strncmp ( ses - > userName , username , MAX_USERNAME_SIZE ) )
2008-05-07 02:05:51 +04:00
continue ;
2008-11-14 21:53:46 +03:00
+ + ses - > ses_count ;
write_unlock ( & cifs_tcp_ses_lock ) ;
return ses ;
}
write_unlock ( & cifs_tcp_ses_lock ) ;
return NULL ;
}
2008-05-07 02:05:51 +04:00
2008-11-14 21:53:46 +03:00
static void
cifs_put_smb_ses ( struct cifsSesInfo * ses )
{
int xid ;
struct TCP_Server_Info * server = ses - > server ;
2008-05-07 02:05:51 +04:00
2008-11-14 21:53:46 +03:00
write_lock ( & cifs_tcp_ses_lock ) ;
if ( - - ses - > ses_count > 0 ) {
write_unlock ( & cifs_tcp_ses_lock ) ;
return ;
}
2008-05-07 02:05:51 +04:00
2008-11-14 21:53:46 +03:00
list_del_init ( & ses - > smb_ses_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2008-05-07 02:05:51 +04:00
2008-11-14 21:53:46 +03:00
if ( ses - > status = = CifsGood ) {
xid = GetXid ( ) ;
CIFSSMBLogoff ( xid , ses ) ;
_FreeXid ( xid ) ;
}
sesInfoFree ( ses ) ;
cifs_put_tcp_session ( server ) ;
}
2008-05-07 02:05:51 +04:00
2008-11-15 19:12:47 +03:00
static struct cifsTconInfo *
cifs_find_tcon ( struct cifsSesInfo * ses , const char * unc )
{
struct list_head * tmp ;
struct cifsTconInfo * tcon ;
write_lock ( & cifs_tcp_ses_lock ) ;
list_for_each ( tmp , & ses - > tcon_list ) {
tcon = list_entry ( tmp , struct cifsTconInfo , tcon_list ) ;
if ( tcon - > tidStatus = = CifsExiting )
continue ;
if ( strncmp ( tcon - > treeName , unc , MAX_TREE_SIZE ) )
2008-05-07 02:05:51 +04:00
continue ;
2008-11-15 19:12:47 +03:00
+ + tcon - > tc_count ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2008-05-07 02:05:51 +04:00
return tcon ;
2005-04-17 02:20:36 +04:00
}
2008-11-15 19:12:47 +03:00
write_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-11-15 19:12:47 +03:00
static void
cifs_put_tcon ( struct cifsTconInfo * tcon )
{
int xid ;
struct cifsSesInfo * ses = tcon - > ses ;
write_lock ( & cifs_tcp_ses_lock ) ;
if ( - - tcon - > tc_count > 0 ) {
write_unlock ( & cifs_tcp_ses_lock ) ;
return ;
}
list_del_init ( & tcon - > tcon_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
xid = GetXid ( ) ;
CIFSSMBTDis ( xid , tcon ) ;
_FreeXid ( xid ) ;
DeleteTconOplockQEntries ( tcon ) ;
tconInfoFree ( tcon ) ;
cifs_put_smb_ses ( ses ) ;
}
2005-04-17 02:20:36 +04:00
int
2007-07-13 04:33:32 +04:00
get_dfs_path ( int xid , struct cifsSesInfo * pSesInfo , const char * old_path ,
const struct nls_table * nls_codepage , unsigned int * pnum_referrals ,
2008-01-25 13:12:41 +03:00
struct dfs_info3_param * * preferrals , int remap )
2005-04-17 02:20:36 +04:00
{
char * temp_unc ;
int rc = 0 ;
* pnum_referrals = 0 ;
2008-01-25 13:12:41 +03:00
* preferrals = NULL ;
2005-04-17 02:20:36 +04:00
if ( pSesInfo - > ipc_tid = = 0 ) {
temp_unc = kmalloc ( 2 /* for slashes */ +
2007-07-13 04:33:32 +04:00
strnlen ( pSesInfo - > serverName ,
SERVER_NAME_LEN_WITH_NULL * 2 )
2005-04-17 02:20:36 +04:00
+ 1 + 4 /* slash IPC$ */ + 2 ,
GFP_KERNEL ) ;
if ( temp_unc = = NULL )
return - ENOMEM ;
temp_unc [ 0 ] = ' \\ ' ;
temp_unc [ 1 ] = ' \\ ' ;
strcpy ( temp_unc + 2 , pSesInfo - > serverName ) ;
strcpy ( temp_unc + 2 + strlen ( pSesInfo - > serverName ) , " \\ IPC$ " ) ;
rc = CIFSTCon ( xid , pSesInfo , temp_unc , NULL , nls_codepage ) ;
cFYI ( 1 ,
2007-07-13 04:33:32 +04:00
( " CIFS Tcon rc = %d ipc_tid = %d " , rc , pSesInfo - > ipc_tid ) ) ;
2005-04-17 02:20:36 +04:00
kfree ( temp_unc ) ;
}
if ( rc = = 0 )
2008-05-15 10:20:02 +04:00
rc = CIFSGetDFSRefer ( xid , pSesInfo , old_path , preferrals ,
2005-04-29 09:41:06 +04:00
pnum_referrals , nls_codepage , remap ) ;
2008-01-25 13:12:41 +03:00
/* BB map targetUNCs to dfs_info3 structures, here or
in CIFSGetDFSRefer BB */
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-07-23 18:11:19 +04:00
# ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key cifs_key [ 2 ] ;
static struct lock_class_key cifs_slock_key [ 2 ] ;
static inline void
cifs_reclassify_socket4 ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
BUG_ON ( sock_owned_by_user ( sk ) ) ;
sock_lock_init_class_and_name ( sk , " slock-AF_INET-CIFS " ,
& cifs_slock_key [ 0 ] , " sk_lock-AF_INET-CIFS " , & cifs_key [ 0 ] ) ;
}
static inline void
cifs_reclassify_socket6 ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
BUG_ON ( sock_owned_by_user ( sk ) ) ;
sock_lock_init_class_and_name ( sk , " slock-AF_INET6-CIFS " ,
& cifs_slock_key [ 1 ] , " sk_lock-AF_INET6-CIFS " , & cifs_key [ 1 ] ) ;
}
# else
static inline void
cifs_reclassify_socket4 ( struct socket * sock )
{
}
static inline void
cifs_reclassify_socket6 ( struct socket * sock )
{
}
# endif
2005-04-17 02:20:36 +04:00
/* See RFC1001 section 14 on representation of Netbios names */
2007-07-13 04:33:32 +04:00
static void rfc1002mangle ( char * target , char * source , unsigned int length )
2005-04-17 02:20:36 +04:00
{
2007-07-13 04:33:32 +04:00
unsigned int i , j ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
for ( i = 0 , j = 0 ; i < ( length ) ; i + + ) {
2005-04-17 02:20:36 +04:00
/* mask a nibble at a time and encode */
target [ j ] = ' A ' + ( 0x0F & ( source [ i ] > > 4 ) ) ;
target [ j + 1 ] = ' A ' + ( 0x0F & source [ i ] ) ;
2007-07-13 04:33:32 +04:00
j + = 2 ;
2005-04-17 02:20:36 +04:00
}
}
static int
2008-12-02 02:42:15 +03:00
ipv4_connect ( struct TCP_Server_Info * server )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2008-12-02 02:42:15 +03:00
bool connected = false ;
2005-04-17 02:20:36 +04:00
__be16 orig_port = 0 ;
2008-12-02 02:42:15 +03:00
struct socket * socket = server - > ssocket ;
2005-04-17 02:20:36 +04:00
2008-12-02 02:42:15 +03:00
if ( socket = = NULL ) {
2007-07-13 04:33:32 +04:00
rc = sock_create_kern ( PF_INET , SOCK_STREAM ,
2008-12-02 02:42:15 +03:00
IPPROTO_TCP , & socket ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Error %d creating socket " , rc ) ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-12-02 02:42:15 +03:00
/* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI ( 1 , ( " Socket created " ) ) ;
server - > ssocket = socket ;
socket - > sk - > sk_allocation = GFP_NOFS ;
cifs_reclassify_socket4 ( socket ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-02 02:42:15 +03:00
/* user overrode default port */
if ( server - > addr . sockAddr . sin_port ) {
rc = socket - > ops - > connect ( socket , ( struct sockaddr * )
& server - > addr . sockAddr ,
sizeof ( struct sockaddr_in ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
2008-12-02 02:42:15 +03:00
connected = true ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-10 05:16:18 +04:00
if ( ! connected ) {
2007-07-13 04:33:32 +04:00
/* save original port so we can retry user specified port
2005-04-17 02:20:36 +04:00
later if fall back ports fail this time */
2008-12-02 02:42:15 +03:00
orig_port = server - > addr . sockAddr . sin_port ;
2005-04-17 02:20:36 +04:00
/* do not retry on the same port we just failed on */
2008-12-02 02:42:15 +03:00
if ( server - > addr . sockAddr . sin_port ! = htons ( CIFS_PORT ) ) {
server - > addr . sockAddr . sin_port = htons ( CIFS_PORT ) ;
rc = socket - > ops - > connect ( socket ,
( struct sockaddr * )
& server - > addr . sockAddr ,
sizeof ( struct sockaddr_in ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
2008-12-02 02:42:15 +03:00
connected = true ;
2005-04-17 02:20:36 +04:00
}
}
if ( ! connected ) {
2008-12-02 02:42:15 +03:00
server - > addr . sockAddr . sin_port = htons ( RFC1001_PORT ) ;
rc = socket - > ops - > connect ( socket , ( struct sockaddr * )
& server - > addr . sockAddr ,
2007-10-16 21:57:55 +04:00
sizeof ( struct sockaddr_in ) , 0 ) ;
2007-07-13 04:33:32 +04:00
if ( rc > = 0 )
2008-12-02 02:42:15 +03:00
connected = true ;
2005-04-17 02:20:36 +04:00
}
/* give up here - unless we want to retry on different
protocol families some day */
if ( ! connected ) {
2007-07-10 05:16:18 +04:00
if ( orig_port )
2008-12-02 02:42:15 +03:00
server - > addr . sockAddr . sin_port = orig_port ;
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Error %d connecting to server via ipv4 " , rc ) ) ;
2008-12-02 02:42:15 +03:00
sock_release ( socket ) ;
server - > ssocket = NULL ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-12-02 02:42:15 +03:00
/*
* Eventually check for other socket options to change from
* the default . sock_setsockopt not used because it expects
* user space buffer
*/
socket - > sk - > sk_rcvtimeo = 7 * HZ ;
2009-01-19 06:49:35 +03:00
socket - > sk - > sk_sndtimeo = 5 * HZ ;
2008-10-29 03:47:57 +03:00
2005-10-11 01:21:15 +04:00
/* make the bufsizes depend on wsize/rsize and max requests */
2008-12-02 02:42:15 +03:00
if ( server - > noautotune ) {
if ( socket - > sk - > sk_sndbuf < ( 200 * 1024 ) )
socket - > sk - > sk_sndbuf = 200 * 1024 ;
if ( socket - > sk - > sk_rcvbuf < ( 140 * 1024 ) )
socket - > sk - > sk_rcvbuf = 140 * 1024 ;
2008-10-29 03:47:57 +03:00
}
2005-04-17 02:20:36 +04:00
2008-12-02 02:42:15 +03:00
cFYI ( 1 , ( " sndbuf %d rcvbuf %d rcvtimeo 0x%lx " ,
socket - > sk - > sk_sndbuf ,
socket - > sk - > sk_rcvbuf , socket - > sk - > sk_rcvtimeo ) ) ;
2005-04-17 02:20:36 +04:00
/* send RFC1001 sessinit */
2008-12-02 02:42:15 +03:00
if ( server - > addr . sockAddr . sin_port = = htons ( RFC1001_PORT ) ) {
2005-04-17 02:20:36 +04:00
/* some servers require RFC1001 sessinit before sending
2007-07-13 04:33:32 +04:00
negprot - BB check reconnection in case where second
2005-04-17 02:20:36 +04:00
sessinit is sent but no second negprot */
2007-07-13 04:33:32 +04:00
struct rfc1002_session_packet * ses_init_buf ;
struct smb_hdr * smb_buf ;
ses_init_buf = kzalloc ( sizeof ( struct rfc1002_session_packet ) ,
GFP_KERNEL ) ;
2007-07-10 05:16:18 +04:00
if ( ses_init_buf ) {
2005-04-17 02:20:36 +04:00
ses_init_buf - > trailer . session_req . called_len = 32 ;
2008-12-02 02:42:15 +03:00
if ( server - > server_RFC1001_name & &
server - > server_RFC1001_name [ 0 ] ! = 0 )
2008-12-01 23:23:50 +03:00
rfc1002mangle ( ses_init_buf - > trailer .
session_req . called_name ,
2008-12-02 02:42:15 +03:00
server - > server_RFC1001_name ,
2008-12-01 23:23:50 +03:00
RFC1001_NAME_LEN_WITH_NULL ) ;
2008-12-02 02:42:15 +03:00
else
2008-12-01 23:23:50 +03:00
rfc1002mangle ( ses_init_buf - > trailer .
session_req . called_name ,
DEFAULT_CIFS_CALLED_NAME ,
RFC1001_NAME_LEN_WITH_NULL ) ;
2005-08-23 08:38:31 +04:00
2005-04-17 02:20:36 +04:00
ses_init_buf - > trailer . session_req . calling_len = 32 ;
2008-12-02 02:42:15 +03:00
2005-04-17 02:20:36 +04:00
/* calling name ends in null (byte 16) from old smb
convention . */
2008-12-02 02:42:15 +03:00
if ( server - > workstation_RFC1001_name & &
server - > workstation_RFC1001_name [ 0 ] ! = 0 )
2008-12-01 23:23:50 +03:00
rfc1002mangle ( ses_init_buf - > trailer .
session_req . calling_name ,
2008-12-02 02:42:15 +03:00
server - > workstation_RFC1001_name ,
2008-12-01 23:23:50 +03:00
RFC1001_NAME_LEN_WITH_NULL ) ;
2008-12-02 02:42:15 +03:00
else
2008-12-01 23:23:50 +03:00
rfc1002mangle ( ses_init_buf - > trailer .
session_req . calling_name ,
" LINUX_CIFS_CLNT " ,
RFC1001_NAME_LEN_WITH_NULL ) ;
2008-12-02 02:42:15 +03:00
2005-04-17 02:20:36 +04:00
ses_init_buf - > trailer . session_req . scope1 = 0 ;
ses_init_buf - > trailer . session_req . scope2 = 0 ;
smb_buf = ( struct smb_hdr * ) ses_init_buf ;
/* sizeof RFC1002_SESSION_REQUEST with no scope */
smb_buf - > smb_buf_length = 0x81000044 ;
2008-12-30 20:39:16 +03:00
rc = smb_send ( server , smb_buf , 0x44 ) ;
2005-04-17 02:20:36 +04:00
kfree ( ses_init_buf ) ;
2007-07-13 04:33:32 +04:00
msleep ( 1 ) ; /* RFC1001 layer in at least one server
2006-03-03 12:53:36 +03:00
requires very short break before negprot
presumably because not expecting negprot
to follow so fast . This is a simple
2007-07-13 04:33:32 +04:00
solution that works without
2006-03-03 12:53:36 +03:00
complicating the code and causes no
significant slowing down on mount
for everyone else */
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
/* else the negprot may still work without this
2005-04-17 02:20:36 +04:00
even though malloc failed */
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
return rc ;
}
static int
2008-12-02 02:42:33 +03:00
ipv6_connect ( struct TCP_Server_Info * server )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2008-12-02 02:42:33 +03:00
bool connected = false ;
2005-04-17 02:20:36 +04:00
__be16 orig_port = 0 ;
2008-12-02 02:42:33 +03:00
struct socket * socket = server - > ssocket ;
2005-04-17 02:20:36 +04:00
2008-12-02 02:42:33 +03:00
if ( socket = = NULL ) {
2007-07-13 04:33:32 +04:00
rc = sock_create_kern ( PF_INET6 , SOCK_STREAM ,
2008-12-02 02:42:33 +03:00
IPPROTO_TCP , & socket ) ;
2005-04-17 02:20:36 +04:00
if ( rc < 0 ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " Error %d creating ipv6 socket " , rc ) ) ;
2008-12-02 02:42:33 +03:00
socket = NULL ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-12-02 02:42:33 +03:00
/* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI ( 1 , ( " ipv6 Socket created " ) ) ;
server - > ssocket = socket ;
socket - > sk - > sk_allocation = GFP_NOFS ;
cifs_reclassify_socket6 ( socket ) ;
}
2005-04-17 02:20:36 +04:00
2008-12-02 02:42:33 +03:00
/* user overrode default port */
if ( server - > addr . sockAddr6 . sin6_port ) {
rc = socket - > ops - > connect ( socket ,
( struct sockaddr * ) & server - > addr . sockAddr6 ,
2007-10-16 21:57:55 +04:00
sizeof ( struct sockaddr_in6 ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
2008-12-02 02:42:33 +03:00
connected = true ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-10 05:16:18 +04:00
if ( ! connected ) {
2007-07-13 04:33:32 +04:00
/* save original port so we can retry user specified port
2005-04-17 02:20:36 +04:00
later if fall back ports fail this time */
2008-12-02 02:42:33 +03:00
orig_port = server - > addr . sockAddr6 . sin6_port ;
2005-04-17 02:20:36 +04:00
/* do not retry on the same port we just failed on */
2008-12-02 02:42:33 +03:00
if ( server - > addr . sockAddr6 . sin6_port ! = htons ( CIFS_PORT ) ) {
server - > addr . sockAddr6 . sin6_port = htons ( CIFS_PORT ) ;
rc = socket - > ops - > connect ( socket , ( struct sockaddr * )
& server - > addr . sockAddr6 ,
2007-10-16 21:57:55 +04:00
sizeof ( struct sockaddr_in6 ) , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc > = 0 )
2008-12-02 02:42:33 +03:00
connected = true ;
2005-04-17 02:20:36 +04:00
}
}
if ( ! connected ) {
2008-12-02 02:42:33 +03:00
server - > addr . sockAddr6 . sin6_port = htons ( RFC1001_PORT ) ;
rc = socket - > ops - > connect ( socket , ( struct sockaddr * )
& server - > addr . sockAddr6 ,
sizeof ( struct sockaddr_in6 ) , 0 ) ;
2007-07-13 04:33:32 +04:00
if ( rc > = 0 )
2008-12-02 02:42:33 +03:00
connected = true ;
2005-04-17 02:20:36 +04:00
}
/* give up here - unless we want to retry on different
protocol families some day */
if ( ! connected ) {
2007-07-10 05:16:18 +04:00
if ( orig_port )
2008-12-02 02:42:33 +03:00
server - > addr . sockAddr6 . sin6_port = orig_port ;
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Error %d connecting to server via ipv6 " , rc ) ) ;
2008-12-02 02:42:33 +03:00
sock_release ( socket ) ;
server - > ssocket = NULL ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-10-29 03:47:57 +03:00
2008-12-02 02:42:33 +03:00
/*
* Eventually check for other socket options to change from
* the default . sock_setsockopt not used because it expects
* user space buffer
*/
socket - > sk - > sk_rcvtimeo = 7 * HZ ;
2009-01-19 06:49:35 +03:00
socket - > sk - > sk_sndtimeo = 5 * HZ ;
2008-12-02 02:42:33 +03:00
server - > ssocket = socket ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
return rc ;
}
2007-07-13 04:33:32 +04:00
void reset_cifs_unix_caps ( int xid , struct cifsTconInfo * tcon ,
struct super_block * sb , struct smb_vol * vol_info )
2007-02-14 07:42:51 +03:00
{
/* if we are reconnecting then should we check to see if
* any requested capabilities changed locally e . g . via
* remount but we can not do much about it here
* if they have ( even if we could detect it by the following )
* Perhaps we could add a backpointer to array of sb from tcon
* or if we change to make all sb to same share the same
* sb as NFS - then we only have one backpointer to sb .
* What if we wanted to mount the server share twice once with
* and once without posixacls or posix paths ? */
__u64 saved_cap = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2007-07-13 04:33:32 +04:00
2007-07-19 03:21:09 +04:00
if ( vol_info & & vol_info - > no_linux_ext ) {
tcon - > fsUnixInfo . Capability = 0 ;
tcon - > unix_ext = 0 ; /* Unix Extensions disabled */
cFYI ( 1 , ( " Linux protocol extensions disabled " ) ) ;
return ;
} else if ( vol_info )
tcon - > unix_ext = 1 ; /* Unix Extensions supported */
if ( tcon - > unix_ext = = 0 ) {
cFYI ( 1 , ( " Unix extensions disabled so not set on reconnect " ) ) ;
return ;
}
2007-07-13 04:33:32 +04:00
2007-07-10 05:16:18 +04:00
if ( ! CIFSSMBQFSUnixInfo ( xid , tcon ) ) {
2007-02-14 07:42:51 +03:00
__u64 cap = le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ;
2007-07-13 04:33:32 +04:00
2007-02-14 07:42:51 +03:00
/* check for reconnect case in which we do not
want to change the mount behavior if we can avoid it */
2007-07-10 05:16:18 +04:00
if ( vol_info = = NULL ) {
2007-07-13 04:33:32 +04:00
/* turn off POSIX ACL and PATHNAMES if not set
2007-02-14 07:42:51 +03:00
originally at mount time */
if ( ( saved_cap & CIFS_UNIX_POSIX_ACL_CAP ) = = 0 )
cap & = ~ CIFS_UNIX_POSIX_ACL_CAP ;
2008-02-15 22:06:04 +03:00
if ( ( saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP ) = = 0 ) {
if ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP )
cERROR ( 1 , ( " POSIXPATH support change " ) ) ;
2007-02-14 07:42:51 +03:00
cap & = ~ CIFS_UNIX_POSIX_PATHNAMES_CAP ;
2008-02-15 22:06:04 +03:00
} else if ( ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP ) = = 0 ) {
cERROR ( 1 , ( " possible reconnect error " ) ) ;
cERROR ( 1 ,
( " server disabled POSIX path support " ) ) ;
}
2007-02-14 07:42:51 +03:00
}
2007-07-13 04:33:32 +04:00
2007-02-14 07:42:51 +03:00
cap & = CIFS_UNIX_CAP_MASK ;
2007-06-24 22:30:48 +04:00
if ( vol_info & & vol_info - > no_psx_acl )
2007-02-14 07:42:51 +03:00
cap & = ~ CIFS_UNIX_POSIX_ACL_CAP ;
2007-06-24 22:30:48 +04:00
else if ( CIFS_UNIX_POSIX_ACL_CAP & cap ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " negotiated posix acl support " ) ) ;
if ( sb )
2007-02-14 07:42:51 +03:00
sb - > s_flags | = MS_POSIXACL ;
}
2007-06-24 22:30:48 +04:00
if ( vol_info & & vol_info - > posix_paths = = 0 )
2007-02-14 07:42:51 +03:00
cap & = ~ CIFS_UNIX_POSIX_PATHNAMES_CAP ;
2007-06-24 22:30:48 +04:00
else if ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " negotiate posix pathnames " ) ) ;
2007-06-24 22:30:48 +04:00
if ( sb )
2007-07-13 04:33:32 +04:00
CIFS_SB ( sb ) - > mnt_cifs_flags | =
2007-02-14 07:42:51 +03:00
CIFS_MOUNT_POSIX_PATHS ;
}
2007-07-13 04:33:32 +04:00
2007-04-26 20:42:50 +04:00
/* We might be setting the path sep back to a different
form if we are reconnecting and the server switched its
2007-07-13 04:33:32 +04:00
posix path capability for this share */
2007-06-24 22:30:48 +04:00
if ( sb & & ( CIFS_SB ( sb ) - > prepathlen > 0 ) )
2007-04-26 20:42:50 +04:00
CIFS_SB ( sb ) - > prepath [ 0 ] = CIFS_DIR_SEP ( CIFS_SB ( sb ) ) ;
2007-06-24 22:30:48 +04:00
if ( sb & & ( CIFS_SB ( sb ) - > rsize > 127 * 1024 ) ) {
if ( ( cap & CIFS_UNIX_LARGE_READ_CAP ) = = 0 ) {
CIFS_SB ( sb ) - > rsize = 127 * 1024 ;
2008-02-12 23:32:36 +03:00
cFYI ( DBG2 ,
( " larger reads not supported by srv " ) ) ;
2007-06-24 22:30:48 +04:00
}
}
2007-07-13 04:33:32 +04:00
cFYI ( 1 , ( " Negotiate caps 0x%x " , ( int ) cap ) ) ;
2007-02-14 07:42:51 +03:00
# ifdef CONFIG_CIFS_DEBUG2
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_FCNTL_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " FCNTL cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_EXTATTR_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " EXTATTR cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_POSIX_PATHNAMES_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " POSIX path cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_XATTR_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " XATTR cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_POSIX_ACL_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " POSIX ACL cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_LARGE_READ_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " very large read cap " ) ) ;
2007-06-24 22:30:48 +04:00
if ( cap & CIFS_UNIX_LARGE_WRITE_CAP )
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " very large write cap " ) ) ;
2007-02-14 07:42:51 +03:00
# endif /* CIFS_DEBUG2 */
if ( CIFSSMBSetFSUnixInfo ( xid , tcon , cap ) ) {
2007-09-25 00:25:46 +04:00
if ( vol_info = = NULL ) {
2007-09-20 19:16:24 +04:00
cFYI ( 1 , ( " resetting capabilities failed " ) ) ;
2007-09-25 00:25:46 +04:00
} else
2007-09-20 19:16:24 +04:00
cERROR ( 1 , ( " Negotiating Unix capabilities "
" with the server failed. Consider "
" mounting with the Unix Extensions \n "
" disabled, if problems are found, "
" by specifying the nounix mount "
2007-09-20 19:37:29 +04:00
" option. " ) ) ;
2007-09-20 19:16:24 +04:00
2007-02-14 07:42:51 +03:00
}
}
}
2008-02-14 09:38:30 +03:00
static void
convert_delimiter ( char * path , char delim )
{
int i ;
2008-02-15 22:20:18 +03:00
char old_delim ;
2008-02-14 09:38:30 +03:00
if ( path = = NULL )
return ;
2008-05-13 08:54:12 +04:00
if ( delim = = ' / ' )
2008-02-15 22:20:18 +03:00
old_delim = ' \\ ' ;
else
old_delim = ' / ' ;
2008-02-14 09:38:30 +03:00
for ( i = 0 ; path [ i ] ! = ' \0 ' ; i + + ) {
2008-02-15 22:20:18 +03:00
if ( path [ i ] = = old_delim )
2008-02-14 09:38:30 +03:00
path [ i ] = delim ;
}
}
2008-11-13 22:45:32 +03:00
static void setup_cifs_sb ( struct smb_vol * pvolume_info ,
struct cifs_sb_info * cifs_sb )
2008-10-22 21:57:07 +04:00
{
2008-11-13 22:45:32 +03:00
if ( pvolume_info - > rsize > CIFSMaxBufSize ) {
cERROR ( 1 , ( " rsize %d too large, using MaxBufSize " ,
pvolume_info - > rsize ) ) ;
cifs_sb - > rsize = CIFSMaxBufSize ;
} else if ( ( pvolume_info - > rsize ) & &
( pvolume_info - > rsize < = CIFSMaxBufSize ) )
cifs_sb - > rsize = pvolume_info - > rsize ;
else /* default */
cifs_sb - > rsize = CIFSMaxBufSize ;
if ( pvolume_info - > wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE ) {
cERROR ( 1 , ( " wsize %d too large, using 4096 instead " ,
pvolume_info - > wsize ) ) ;
cifs_sb - > wsize = 4096 ;
} else if ( pvolume_info - > wsize )
cifs_sb - > wsize = pvolume_info - > wsize ;
else
cifs_sb - > wsize = min_t ( const int ,
PAGEVEC_SIZE * PAGE_CACHE_SIZE ,
127 * 1024 ) ;
/* old default of CIFSMaxBufSize was too small now
that SMB Write2 can send multiple pages in kvec .
RFC1001 does not describe what happens when frame
bigger than 128 K is sent so use that as max in
conjunction with 52 K kvec constraint on arch with 4 K
page size */
if ( cifs_sb - > rsize < 2048 ) {
cifs_sb - > rsize = 2048 ;
/* Windows ME may prefer this */
cFYI ( 1 , ( " readsize set to minimum: 2048 " ) ) ;
}
/* calculate prepath */
cifs_sb - > prepath = pvolume_info - > prepath ;
if ( cifs_sb - > prepath ) {
cifs_sb - > prepathlen = strlen ( cifs_sb - > prepath ) ;
/* we can not convert the / to \ in the path
separators in the prefixpath yet because we do not
know ( until reset_cifs_unix_caps is called later )
whether POSIX PATH CAP is available . We normalize
the / to \ after reset_cifs_unix_caps is called */
pvolume_info - > prepath = NULL ;
} else
cifs_sb - > prepathlen = 0 ;
cifs_sb - > mnt_uid = pvolume_info - > linux_uid ;
cifs_sb - > mnt_gid = pvolume_info - > linux_gid ;
cifs_sb - > mnt_file_mode = pvolume_info - > file_mode ;
cifs_sb - > mnt_dir_mode = pvolume_info - > dir_mode ;
cFYI ( 1 , ( " file mode: 0x%x dir mode: 0x%x " ,
cifs_sb - > mnt_file_mode , cifs_sb - > mnt_dir_mode ) ) ;
if ( pvolume_info - > noperm )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_PERM ;
if ( pvolume_info - > setuids )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_SET_UID ;
if ( pvolume_info - > server_ino )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_SERVER_INUM ;
if ( pvolume_info - > remap )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_MAP_SPECIAL_CHR ;
if ( pvolume_info - > no_xattr )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_XATTR ;
if ( pvolume_info - > sfu_emul )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_UNX_EMUL ;
if ( pvolume_info - > nobrl )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NO_BRL ;
2009-02-23 18:21:59 +03:00
if ( pvolume_info - > nostrictsync )
2009-02-24 17:44:19 +03:00
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NOSSYNC ;
2008-12-02 20:24:33 +03:00
if ( pvolume_info - > mand_lock )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_NOPOSIXBRL ;
2008-11-13 22:45:32 +03:00
if ( pvolume_info - > cifs_acl )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_CIFS_ACL ;
if ( pvolume_info - > override_uid )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_OVERR_UID ;
if ( pvolume_info - > override_gid )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_OVERR_GID ;
if ( pvolume_info - > dynperm )
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_DYNPERM ;
if ( pvolume_info - > direct_io ) {
cFYI ( 1 , ( " mounting share using direct i/o " ) ) ;
cifs_sb - > mnt_cifs_flags | = CIFS_MOUNT_DIRECT_IO ;
}
if ( ( pvolume_info - > cifs_acl ) & & ( pvolume_info - > dynperm ) )
cERROR ( 1 , ( " mount option dynperm ignored if cifsacl "
" mount option supported " ) ) ;
2008-10-22 21:57:07 +04:00
}
2009-02-10 14:10:26 +03:00
static int
is_path_accessible ( int xid , struct cifsTconInfo * tcon ,
struct cifs_sb_info * cifs_sb , const char * full_path )
{
int rc ;
__u64 inode_num ;
FILE_ALL_INFO * pfile_info ;
rc = CIFSGetSrvInodeNumber ( xid , tcon , full_path , & inode_num ,
cifs_sb - > local_nls ,
cifs_sb - > mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
if ( rc ! = - EOPNOTSUPP )
return rc ;
pfile_info = kmalloc ( sizeof ( FILE_ALL_INFO ) , GFP_KERNEL ) ;
if ( pfile_info = = NULL )
return - ENOMEM ;
rc = CIFSSMBQPathInfo ( xid , tcon , full_path , pfile_info ,
0 /* not legacy */ , cifs_sb - > local_nls ,
cifs_sb - > mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
kfree ( pfile_info ) ;
return rc ;
}
2009-04-01 17:54:42 +04:00
static void
cleanup_volume_info ( struct smb_vol * * pvolume_info )
{
struct smb_vol * volume_info ;
if ( ! pvolume_info & & ! * pvolume_info )
return ;
volume_info = * pvolume_info ;
kzfree ( volume_info - > password ) ;
kfree ( volume_info - > UNC ) ;
kfree ( volume_info - > prepath ) ;
kfree ( volume_info ) ;
* pvolume_info = NULL ;
return ;
}
2009-04-09 04:36:44 +04:00
# ifdef CONFIG_CIFS_DFS_UPCALL
2009-04-01 17:54:42 +04:00
/* build_path_to_root returns full path to root when
* we do not have an exiting connection ( tcon ) */
static char *
build_unc_path_to_root ( const struct smb_vol * volume_info ,
const struct cifs_sb_info * cifs_sb )
{
char * full_path ;
int unc_len = strnlen ( volume_info - > UNC , MAX_TREE_SIZE + 1 ) ;
full_path = kmalloc ( unc_len + cifs_sb - > prepathlen + 1 , GFP_KERNEL ) ;
if ( full_path = = NULL )
return ERR_PTR ( - ENOMEM ) ;
strncpy ( full_path , volume_info - > UNC , unc_len ) ;
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS ) {
int i ;
for ( i = 0 ; i < unc_len ; i + + ) {
if ( full_path [ i ] = = ' \\ ' )
full_path [ i ] = ' / ' ;
}
}
if ( cifs_sb - > prepathlen )
strncpy ( full_path + unc_len , cifs_sb - > prepath ,
cifs_sb - > prepathlen ) ;
full_path [ unc_len + cifs_sb - > prepathlen ] = 0 ; /* add trailing null */
return full_path ;
}
2009-04-09 04:36:44 +04:00
# endif
2009-04-01 17:54:42 +04:00
2005-04-17 02:20:36 +04:00
int
cifs_mount ( struct super_block * sb , struct cifs_sb_info * cifs_sb ,
2009-04-01 17:54:42 +04:00
char * mount_data_global , const char * devname )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
int xid ;
2008-12-02 02:41:49 +03:00
struct smb_vol * volume_info ;
2005-04-17 02:20:36 +04:00
struct cifsSesInfo * pSesInfo = NULL ;
struct cifsTconInfo * tcon = NULL ;
struct TCP_Server_Info * srvTcp = NULL ;
2009-02-10 14:10:26 +03:00
char * full_path ;
2009-04-09 04:36:44 +04:00
char * mount_data = mount_data_global ;
# ifdef CONFIG_CIFS_DFS_UPCALL
2009-04-01 17:54:42 +04:00
struct dfs_info3_param * referrals = NULL ;
unsigned int num_referrals = 0 ;
2009-04-21 19:31:05 +04:00
int referral_walks_count = 0 ;
2009-04-01 17:54:42 +04:00
try_mount_again :
2009-04-09 04:36:44 +04:00
# endif
2009-04-01 17:54:42 +04:00
full_path = NULL ;
2005-04-17 02:20:36 +04:00
xid = GetXid ( ) ;
2008-12-02 02:41:49 +03:00
volume_info = kzalloc ( sizeof ( struct smb_vol ) , GFP_KERNEL ) ;
if ( ! volume_info ) {
rc = - ENOMEM ;
goto out ;
}
2007-07-13 04:33:32 +04:00
2008-12-02 02:41:49 +03:00
if ( cifs_parse_mount_options ( mount_data , devname , volume_info ) ) {
2007-11-17 01:21:07 +03:00
rc = - EINVAL ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-12-02 02:41:49 +03:00
if ( volume_info - > nullauth ) {
2007-07-10 05:16:18 +04:00
cFYI ( 1 , ( " null user " ) ) ;
2008-12-02 02:41:49 +03:00
volume_info - > username = " " ;
} else if ( volume_info - > username ) {
2005-04-17 02:20:36 +04:00
/* BB fixme parse for domain name here */
2008-12-02 02:41:49 +03:00
cFYI ( 1 , ( " Username: %s " , volume_info - > username ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-12-02 09:32:42 +03:00
cifserror ( " No username specified " ) ;
2007-07-13 04:33:32 +04:00
/* In userspace mount helper we can get user name from alternate
locations such as env variables and files on disk */
2007-11-17 01:21:07 +03:00
rc = - EINVAL ;
goto out ;
2005-04-17 02:20:36 +04:00
}
/* this is needed for ASCII cp to Unicode converts */
2008-12-02 02:41:49 +03:00
if ( volume_info - > iocharset = = NULL ) {
2005-04-17 02:20:36 +04:00
cifs_sb - > local_nls = load_nls_default ( ) ;
/* load_nls_default can not return null */
} else {
2008-12-02 02:41:49 +03:00
cifs_sb - > local_nls = load_nls ( volume_info - > iocharset ) ;
2007-07-10 05:16:18 +04:00
if ( cifs_sb - > local_nls = = NULL ) {
2007-07-13 04:33:32 +04:00
cERROR ( 1 , ( " CIFS mount error: iocharset %s not found " ,
2008-12-02 02:41:49 +03:00
volume_info - > iocharset ) ) ;
2007-11-17 01:21:07 +03:00
rc = - ELIBACC ;
goto out ;
2005-04-17 02:20:36 +04:00
}
}
2008-12-02 02:41:46 +03:00
/* get a reference to a tcp session */
2008-12-02 02:41:49 +03:00
srvTcp = cifs_get_tcp_session ( volume_info ) ;
2008-12-02 02:41:46 +03:00
if ( IS_ERR ( srvTcp ) ) {
rc = PTR_ERR ( srvTcp ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-12-02 02:41:49 +03:00
pSesInfo = cifs_find_smb_ses ( srvTcp , volume_info - > username ) ;
2008-11-14 21:53:46 +03:00
if ( pSesInfo ) {
2007-12-31 04:37:11 +03:00
cFYI ( 1 , ( " Existing smb sess found (status=%d) " ,
pSesInfo - > status ) ) ;
2008-11-14 21:53:46 +03:00
/*
* The existing SMB session already has a reference to srvTcp ,
* so we can put back the extra one we got before
*/
cifs_put_tcp_session ( srvTcp ) ;
2008-01-03 20:37:09 +03:00
down ( & pSesInfo - > sesSem ) ;
2008-11-13 22:45:32 +03:00
if ( pSesInfo - > need_reconnect ) {
2007-12-31 04:37:11 +03:00
cFYI ( 1 , ( " Session needs reconnect " ) ) ;
rc = cifs_setup_session ( xid , pSesInfo ,
cifs_sb - > local_nls ) ;
}
2008-01-03 20:37:09 +03:00
up ( & pSesInfo - > sesSem ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! rc ) {
2005-12-02 09:32:42 +03:00
cFYI ( 1 , ( " Existing smb sess not found " ) ) ;
2005-04-17 02:20:36 +04:00
pSesInfo = sesInfoAlloc ( ) ;
2008-11-14 21:53:46 +03:00
if ( pSesInfo = = NULL ) {
2005-04-17 02:20:36 +04:00
rc = - ENOMEM ;
2008-11-14 21:53:46 +03:00
goto mount_fail_check ;
2005-04-17 02:20:36 +04:00
}
2008-11-14 21:53:46 +03:00
/* new SMB session uses our srvTcp ref */
pSesInfo - > server = srvTcp ;
2008-12-02 02:41:46 +03:00
if ( srvTcp - > addr . sockAddr6 . sin6_family = = AF_INET6 )
2008-12-28 23:49:40 +03:00
sprintf ( pSesInfo - > serverName , " %pI6 " ,
& srvTcp - > addr . sockAddr6 . sin6_addr ) ;
2008-12-01 23:23:50 +03:00
else
2008-12-28 23:49:40 +03:00
sprintf ( pSesInfo - > serverName , " %pI4 " ,
& srvTcp - > addr . sockAddr . sin_addr . s_addr ) ;
2008-11-14 21:53:46 +03:00
write_lock ( & cifs_tcp_ses_lock ) ;
list_add ( & pSesInfo - > smb_ses_list , & srvTcp - > smb_ses_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2008-12-02 02:41:49 +03:00
/* volume_info->password freed at unmount */
if ( volume_info - > password ) {
2008-12-06 04:41:21 +03:00
pSesInfo - > password = kstrdup ( volume_info - > password ,
GFP_KERNEL ) ;
if ( ! pSesInfo - > password ) {
rc = - ENOMEM ;
goto mount_fail_check ;
}
2008-11-14 21:53:46 +03:00
}
2008-12-02 02:41:49 +03:00
if ( volume_info - > username )
strncpy ( pSesInfo - > userName , volume_info - > username ,
2008-11-14 21:53:46 +03:00
MAX_USERNAME_SIZE ) ;
2008-12-02 02:41:49 +03:00
if ( volume_info - > domainname ) {
int len = strlen ( volume_info - > domainname ) ;
2008-11-14 21:53:46 +03:00
pSesInfo - > domainName = kmalloc ( len + 1 , GFP_KERNEL ) ;
if ( pSesInfo - > domainName )
strcpy ( pSesInfo - > domainName ,
2008-12-02 02:41:49 +03:00
volume_info - > domainname ) ;
2007-11-17 01:21:07 +03:00
}
2008-12-02 02:41:49 +03:00
pSesInfo - > linux_uid = volume_info - > linux_uid ;
pSesInfo - > overrideSecFlg = volume_info - > secFlg ;
2008-11-14 21:53:46 +03:00
down ( & pSesInfo - > sesSem ) ;
2005-04-17 02:20:36 +04:00
2008-11-14 21:53:46 +03:00
/* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session ( xid , pSesInfo ,
cifs_sb - > local_nls ) ;
up ( & pSesInfo - > sesSem ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
/* search for existing tcon to this server share */
if ( ! rc ) {
2008-12-02 02:41:49 +03:00
setup_cifs_sb ( volume_info , cifs_sb ) ;
2005-04-17 02:20:36 +04:00
2008-12-02 02:41:49 +03:00
tcon = cifs_find_tcon ( pSesInfo , volume_info - > UNC ) ;
2005-04-17 02:20:36 +04:00
if ( tcon ) {
2005-12-02 09:32:42 +03:00
cFYI ( 1 , ( " Found match on UNC path " ) ) ;
2008-11-15 19:12:47 +03:00
/* existing tcon already has a reference */
cifs_put_smb_ses ( pSesInfo ) ;
2008-12-02 02:41:49 +03:00
if ( tcon - > seal ! = volume_info - > seal )
2008-05-15 20:44:38 +04:00
cERROR ( 1 , ( " transport encryption setting "
" conflicts with existing tid " ) ) ;
2005-04-17 02:20:36 +04:00
} else {
tcon = tconInfoAlloc ( ) ;
2008-11-13 22:45:32 +03:00
if ( tcon = = NULL ) {
2005-04-17 02:20:36 +04:00
rc = - ENOMEM ;
2008-11-13 22:45:32 +03:00
goto mount_fail_check ;
}
2008-12-06 04:41:21 +03:00
2008-11-17 19:03:00 +03:00
tcon - > ses = pSesInfo ;
2008-12-06 04:41:21 +03:00
if ( volume_info - > password ) {
tcon - > password = kstrdup ( volume_info - > password ,
GFP_KERNEL ) ;
if ( ! tcon - > password ) {
rc = - ENOMEM ;
goto mount_fail_check ;
}
}
2008-11-13 22:45:32 +03:00
2008-12-02 02:41:49 +03:00
if ( ( strchr ( volume_info - > UNC + 3 , ' \\ ' ) = = NULL )
& & ( strchr ( volume_info - > UNC + 3 , ' / ' ) = = NULL ) ) {
2009-04-01 17:54:42 +04:00
cERROR ( 1 , ( " Missing share name " ) ) ;
2008-11-13 22:45:32 +03:00
rc = - ENODEV ;
goto mount_fail_check ;
} else {
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect ? */
2008-12-02 02:41:49 +03:00
rc = CIFSTCon ( xid , pSesInfo , volume_info - > UNC ,
2008-11-13 22:45:32 +03:00
tcon , cifs_sb - > local_nls ) ;
cFYI ( 1 , ( " CIFS Tcon rc = %d " , rc ) ) ;
2008-12-02 02:41:49 +03:00
if ( volume_info - > nodfs ) {
2008-11-13 22:45:32 +03:00
tcon - > Flags & = ~ SMB_SHARE_IS_IN_DFS ;
cFYI ( 1 , ( " DFS disabled (%d) " ,
tcon - > Flags ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-11-14 21:53:46 +03:00
if ( rc )
2009-04-01 17:54:42 +04:00
goto remote_path_check ;
2008-12-02 02:41:49 +03:00
tcon - > seal = volume_info - > seal ;
2008-11-15 19:12:47 +03:00
write_lock ( & cifs_tcp_ses_lock ) ;
list_add ( & tcon - > tcon_list , & pSesInfo - > tcon_list ) ;
write_unlock ( & cifs_tcp_ses_lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-11-13 22:45:32 +03:00
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
to the same server share the last value passed in
for the retry flag is used */
2008-12-02 02:41:49 +03:00
tcon - > retry = volume_info - > retry ;
tcon - > nocase = volume_info - > nocase ;
tcon - > local_lease = volume_info - > local_lease ;
2005-04-17 02:20:36 +04:00
}
2007-05-01 00:13:06 +04:00
if ( pSesInfo ) {
2005-04-17 02:20:36 +04:00
if ( pSesInfo - > capabilities & CAP_LARGE_FILES ) {
sb - > s_maxbytes = ( u64 ) 1 < < 63 ;
} else
sb - > s_maxbytes = ( u64 ) 1 < < 31 ; /* 2 GB */
}
2007-02-14 07:42:51 +03:00
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
2005-04-17 02:20:36 +04:00
sb - > s_time_gran = 100 ;
2009-04-01 17:54:42 +04:00
if ( rc )
goto remote_path_check ;
2008-11-15 03:07:26 +03:00
cifs_sb - > tcon = tcon ;
2007-07-19 03:21:09 +04:00
2008-11-15 03:07:26 +03:00
/* do not care if following two calls succeed - informational */
if ( ! tcon - > ipc ) {
CIFSSMBQFSDeviceInfo ( xid , tcon ) ;
CIFSSMBQFSAttributeInfo ( xid , tcon ) ;
}
2008-02-14 09:38:30 +03:00
2008-11-15 03:07:26 +03:00
/* tell server which Unix caps we support */
if ( tcon - > ses - > capabilities & CAP_UNIX )
/* reset of caps checks mount to see if unix extensions
disabled for just this mount */
2008-12-02 02:41:49 +03:00
reset_cifs_unix_caps ( xid , tcon , sb , volume_info ) ;
2008-11-15 03:07:26 +03:00
else
tcon - > unix_ext = 0 ; /* server does not support them */
2007-07-19 03:21:09 +04:00
2008-11-15 03:07:26 +03:00
/* convert forward to back slashes in prepath here if needed */
if ( ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS ) = = 0 )
convert_delimiter ( cifs_sb - > prepath , CIFS_DIR_SEP ( cifs_sb ) ) ;
2008-02-14 09:38:30 +03:00
2008-11-15 03:07:26 +03:00
if ( ( tcon - > unix_ext = = 0 ) & & ( cifs_sb - > rsize > ( 1024 * 127 ) ) ) {
cifs_sb - > rsize = 1024 * 127 ;
cFYI ( DBG2 , ( " no very large read support, rsize now 127K " ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-11-15 03:07:26 +03:00
if ( ! ( tcon - > ses - > capabilities & CAP_LARGE_WRITE_X ) )
cifs_sb - > wsize = min ( cifs_sb - > wsize ,
( tcon - > ses - > server - > maxBuf - MAX_CIFS_HDR_SIZE ) ) ;
if ( ! ( tcon - > ses - > capabilities & CAP_LARGE_READ_X ) )
cifs_sb - > rsize = min ( cifs_sb - > rsize ,
( tcon - > ses - > server - > maxBuf - MAX_CIFS_HDR_SIZE ) ) ;
2005-04-17 02:20:36 +04:00
2009-04-01 17:54:42 +04:00
remote_path_check :
/* check if a whole path (including prepath) is not remote */
if ( ! rc & & cifs_sb - > prepathlen & & tcon ) {
2009-02-10 14:10:26 +03:00
/* build_path_to_root works only when we have a valid tcon */
full_path = cifs_build_path_to_root ( cifs_sb ) ;
if ( full_path = = NULL ) {
rc = - ENOMEM ;
goto mount_fail_check ;
}
rc = is_path_accessible ( xid , tcon , cifs_sb , full_path ) ;
2009-04-01 17:54:42 +04:00
if ( rc ! = - EREMOTE ) {
2009-02-10 14:10:26 +03:00
kfree ( full_path ) ;
goto mount_fail_check ;
}
kfree ( full_path ) ;
}
2009-04-01 17:54:42 +04:00
/* get referral if needed */
if ( rc = = - EREMOTE ) {
2009-04-03 07:12:08 +04:00
# ifdef CONFIG_CIFS_DFS_UPCALL
2009-04-21 19:31:05 +04:00
if ( referral_walks_count > MAX_NESTED_LINKS ) {
/*
* BB : when we implement proper loop detection ,
* we will remove this check . But now we need it
* to prevent an indefinite loop if ' DFS tree ' is
* misconfigured ( i . e . has loops ) .
*/
rc = - ELOOP ;
goto mount_fail_check ;
}
2009-04-01 17:54:42 +04:00
/* convert forward to back slashes in prepath here if needed */
if ( ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS ) = = 0 )
convert_delimiter ( cifs_sb - > prepath ,
CIFS_DIR_SEP ( cifs_sb ) ) ;
full_path = build_unc_path_to_root ( volume_info , cifs_sb ) ;
if ( IS_ERR ( full_path ) ) {
rc = PTR_ERR ( full_path ) ;
goto mount_fail_check ;
}
cFYI ( 1 , ( " Getting referral for: %s " , full_path ) ) ;
rc = get_dfs_path ( xid , pSesInfo , full_path + 1 ,
cifs_sb - > local_nls , & num_referrals , & referrals ,
cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
if ( ! rc & & num_referrals > 0 ) {
char * fake_devname = NULL ;
if ( mount_data ! = mount_data_global )
kfree ( mount_data ) ;
mount_data = cifs_compose_mount_options (
cifs_sb - > mountdata , full_path + 1 ,
referrals , & fake_devname ) ;
kfree ( fake_devname ) ;
free_dfs_info_array ( referrals , num_referrals ) ;
if ( tcon )
cifs_put_tcon ( tcon ) ;
else if ( pSesInfo )
cifs_put_smb_ses ( pSesInfo ) ;
cleanup_volume_info ( & volume_info ) ;
FreeXid ( xid ) ;
kfree ( full_path ) ;
2009-04-21 19:31:05 +04:00
referral_walks_count + + ;
2009-04-01 17:54:42 +04:00
goto try_mount_again ;
}
2009-04-03 07:12:08 +04:00
# else /* No DFS support, return error on mount */
rc = - EOPNOTSUPP ;
# endif
2009-04-01 17:54:42 +04:00
}
mount_fail_check :
/* on error free sesinfo and tcon struct if needed */
if ( rc ) {
if ( mount_data ! = mount_data_global )
kfree ( mount_data ) ;
/* If find_unc succeeded then rc == 0 so we can not end */
/* up accidently freeing someone elses tcon struct */
if ( tcon )
cifs_put_tcon ( tcon ) ;
else if ( pSesInfo )
cifs_put_smb_ses ( pSesInfo ) ;
else
cifs_put_tcp_session ( srvTcp ) ;
goto out ;
}
2008-12-02 02:41:49 +03:00
/* volume_info->password is freed above when existing session found
2005-04-17 02:20:36 +04:00
( in which case it is not needed anymore ) but when new sesion is created
the password ptr is put in the new session structure ( in which case the
password will be freed at unmount time ) */
2007-11-17 01:21:07 +03:00
out :
/* zero out password before freeing */
2009-04-01 17:54:42 +04:00
cleanup_volume_info ( & volume_info ) ;
2005-04-17 02:20:36 +04:00
FreeXid ( xid ) ;
return rc ;
}
int
CIFSTCon ( unsigned int xid , struct cifsSesInfo * ses ,
const char * tree , struct cifsTconInfo * tcon ,
const struct nls_table * nls_codepage )
{
struct smb_hdr * smb_buffer ;
struct smb_hdr * smb_buffer_response ;
TCONX_REQ * pSMB ;
TCONX_RSP * pSMBr ;
unsigned char * bcc_ptr ;
int rc = 0 ;
2009-04-30 15:16:21 +04:00
int length , bytes_left ;
2005-04-17 02:20:36 +04:00
__u16 count ;
if ( ses = = NULL )
return - EIO ;
smb_buffer = cifs_buf_get ( ) ;
if ( smb_buffer = = NULL ) {
return - ENOMEM ;
}
smb_buffer_response = smb_buffer ;
header_assemble ( smb_buffer , SMB_COM_TREE_CONNECT_ANDX ,
NULL /*no tid */ , 4 /*wct */ ) ;
2005-08-17 23:38:22 +04:00
smb_buffer - > Mid = GetNextMid ( ses - > server ) ;
2005-04-17 02:20:36 +04:00
smb_buffer - > Uid = ses - > Suid ;
pSMB = ( TCONX_REQ * ) smb_buffer ;
pSMBr = ( TCONX_RSP * ) smb_buffer_response ;
pSMB - > AndXCommand = 0xFF ;
pSMB - > Flags = cpu_to_le16 ( TCON_EXTENDED_SECINFO ) ;
bcc_ptr = & pSMB - > Password [ 0 ] ;
2007-07-10 05:16:18 +04:00
if ( ( ses - > server - > secMode ) & SECMODE_USER ) {
2006-01-14 08:34:58 +03:00
pSMB - > PasswordLength = cpu_to_le16 ( 1 ) ; /* minimum */
2006-06-01 23:20:10 +04:00
* bcc_ptr = 0 ; /* password is null byte */
2006-01-14 08:34:58 +03:00
bcc_ptr + + ; /* skip password */
2006-06-01 23:20:10 +04:00
/* already aligned so no need to do it below */
2006-01-14 08:34:58 +03:00
} else {
2006-06-01 23:20:10 +04:00
pSMB - > PasswordLength = cpu_to_le16 ( CIFS_SESS_KEY_SIZE ) ;
2006-01-14 08:34:58 +03:00
/* BB FIXME add code to fail this if NTLMv2 or Kerberos
specified as required ( when that support is added to
the vfs in the future ) as only NTLM or the much
2006-06-01 23:20:10 +04:00
weaker LANMAN ( which we do not send by default ) is accepted
2006-01-14 08:34:58 +03:00
by Samba ( not sure whether other servers allow
NTLMv2 password here ) */
2006-06-01 23:20:10 +04:00
# ifdef CONFIG_CIFS_WEAK_PW_HASH
2007-07-13 04:33:32 +04:00
if ( ( extended_security & CIFSSEC_MAY_LANMAN ) & &
2008-12-06 04:41:21 +03:00
( ses - > server - > secType = = LANMAN ) )
calc_lanman_hash ( tcon - > password , ses - > server - > cryptKey ,
2008-12-06 04:41:21 +03:00
ses - > server - > secMode &
SECMODE_PW_ENCRYPT ? true : false ,
bcc_ptr ) ;
2006-06-01 23:20:10 +04:00
else
# endif /* CIFS_WEAK_PW_HASH */
2008-12-06 04:41:21 +03:00
SMBNTencrypt ( tcon - > password , ses - > server - > cryptKey ,
2006-01-14 08:34:58 +03:00
bcc_ptr ) ;
2006-06-01 23:20:10 +04:00
bcc_ptr + = CIFS_SESS_KEY_SIZE ;
2007-07-10 05:16:18 +04:00
if ( ses - > capabilities & CAP_UNICODE ) {
2006-06-01 23:20:10 +04:00
/* must align unicode strings */
* bcc_ptr = 0 ; /* null byte password */
bcc_ptr + + ;
}
2006-01-14 08:34:58 +03:00
}
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
if ( ses - > server - > secMode &
2006-05-30 22:04:19 +04:00
( SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED ) )
2005-04-17 02:20:36 +04:00
smb_buffer - > Flags2 | = SMBFLG2_SECURITY_SIGNATURE ;
if ( ses - > capabilities & CAP_STATUS32 ) {
smb_buffer - > Flags2 | = SMBFLG2_ERR_STATUS ;
}
if ( ses - > capabilities & CAP_DFS ) {
smb_buffer - > Flags2 | = SMBFLG2_DFS ;
}
if ( ses - > capabilities & CAP_UNICODE ) {
smb_buffer - > Flags2 | = SMBFLG2_UNICODE ;
length =
2007-07-13 04:33:32 +04:00
cifs_strtoUCS ( ( __le16 * ) bcc_ptr , tree ,
6 /* max utf8 char length in bytes */ *
2006-05-30 22:04:19 +04:00
( /* server len*/ + 256 /* share len */ ) , nls_codepage ) ;
bcc_ptr + = 2 * length ; /* convert num 16 bit words to bytes */
2005-04-17 02:20:36 +04:00
bcc_ptr + = 2 ; /* skip trailing null */
} else { /* ASCII */
strcpy ( bcc_ptr , tree ) ;
bcc_ptr + = strlen ( tree ) + 1 ;
}
strcpy ( bcc_ptr , " ????? " ) ;
bcc_ptr + = strlen ( " ????? " ) ;
bcc_ptr + = 1 ;
count = bcc_ptr - & pSMB - > Password [ 0 ] ;
pSMB - > hdr . smb_buf_length + = count ;
pSMB - > ByteCount = cpu_to_le16 ( count ) ;
2007-11-14 01:41:37 +03:00
rc = SendReceive ( xid , ses , smb_buffer , smb_buffer_response , & length ,
CIFS_STD_OP ) ;
2005-04-17 02:20:36 +04:00
/* above now done in SendReceive */
if ( ( rc = = 0 ) & & ( tcon ! = NULL ) ) {
2009-05-01 09:27:32 +04:00
bool is_unicode ;
2005-04-17 02:20:36 +04:00
tcon - > tidStatus = CifsGood ;
2008-11-13 22:45:32 +03:00
tcon - > need_reconnect = false ;
2005-04-17 02:20:36 +04:00
tcon - > tid = smb_buffer_response - > Tid ;
bcc_ptr = pByteArea ( smb_buffer_response ) ;
2009-04-30 15:16:21 +04:00
bytes_left = BCC ( smb_buffer_response ) ;
length = strnlen ( bcc_ptr , bytes_left - 2 ) ;
2009-05-01 09:27:32 +04:00
if ( smb_buffer - > Flags2 & SMBFLG2_UNICODE )
is_unicode = true ;
else
is_unicode = false ;
2009-04-30 15:16:21 +04:00
2007-07-13 04:33:32 +04:00
/* skip service field (NB: this field is always ASCII) */
2007-09-29 02:28:55 +04:00
if ( length = = 3 ) {
if ( ( bcc_ptr [ 0 ] = = ' I ' ) & & ( bcc_ptr [ 1 ] = = ' P ' ) & &
( bcc_ptr [ 2 ] = = ' C ' ) ) {
cFYI ( 1 , ( " IPC connection " ) ) ;
tcon - > ipc = 1 ;
}
} else if ( length = = 2 ) {
if ( ( bcc_ptr [ 0 ] = = ' A ' ) & & ( bcc_ptr [ 1 ] = = ' : ' ) ) {
/* the most common case */
cFYI ( 1 , ( " disk share connection " ) ) ;
}
}
2007-07-13 04:33:32 +04:00
bcc_ptr + = length + 1 ;
2009-04-30 15:16:21 +04:00
bytes_left - = ( length + 1 ) ;
2005-04-17 02:20:36 +04:00
strncpy ( tcon - > treeName , tree , MAX_TREE_SIZE ) ;
2009-04-30 15:16:21 +04:00
/* mostly informational -- no need to fail on error here */
2009-04-30 21:45:10 +04:00
tcon - > nativeFileSystem = cifs_strndup_from_ucs ( bcc_ptr ,
2009-05-01 09:27:32 +04:00
bytes_left , is_unicode ,
2009-04-30 15:16:21 +04:00
nls_codepage ) ;
cFYI ( 1 , ( " nativeFileSystem=%s " , tcon - > nativeFileSystem ) ) ;
2007-07-10 05:16:18 +04:00
if ( ( smb_buffer_response - > WordCount = = 3 ) | |
2006-10-13 01:33:51 +04:00
( smb_buffer_response - > WordCount = = 7 ) )
/* field is in same location */
2006-06-01 02:40:51 +04:00
tcon - > Flags = le16_to_cpu ( pSMBr - > OptionalSupport ) ;
else
tcon - > Flags = 0 ;
2005-04-17 02:20:36 +04:00
cFYI ( 1 , ( " Tcon flags: 0x%x " , tcon - > Flags ) ) ;
} else if ( ( rc = = 0 ) & & tcon = = NULL ) {
2007-07-13 04:33:32 +04:00
/* all we need to save for IPC$ connection */
2005-04-17 02:20:36 +04:00
ses - > ipc_tid = smb_buffer_response - > Tid ;
}
2007-10-03 20:41:24 +04:00
cifs_buf_release ( smb_buffer ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
int
cifs_umount ( struct super_block * sb , struct cifs_sb_info * cifs_sb )
{
int rc = 0 ;
2007-07-13 04:33:32 +04:00
char * tmp ;
2005-04-17 02:20:36 +04:00
2008-11-15 19:12:47 +03:00
if ( cifs_sb - > tcon )
cifs_put_tcon ( cifs_sb - > tcon ) ;
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
cifs_sb - > tcon = NULL ;
2006-09-21 11:02:52 +04:00
tmp = cifs_sb - > prepath ;
cifs_sb - > prepathlen = 0 ;
cifs_sb - > prepath = NULL ;
kfree ( tmp ) ;
2005-04-17 02:20:36 +04:00
2008-01-03 20:37:09 +03:00
return rc ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
int cifs_setup_session ( unsigned int xid , struct cifsSesInfo * pSesInfo ,
2007-07-13 04:33:32 +04:00
struct nls_table * nls_info )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2005-04-29 09:41:05 +04:00
int first_time = 0 ;
2008-08-18 23:41:05 +04:00
struct TCP_Server_Info * server = pSesInfo - > server ;
2005-04-17 02:20:36 +04:00
/* what if server changes its buffer size after dropping the session? */
2008-08-18 23:41:05 +04:00
if ( server - > maxBuf = = 0 ) /* no need to send on reconnect */ {
2005-04-17 02:20:36 +04:00
rc = CIFSSMBNegotiate ( xid , pSesInfo ) ;
2008-08-18 23:41:05 +04:00
if ( rc = = - EAGAIN ) {
/* retry only once on 1st time connection */
2005-04-17 02:20:36 +04:00
rc = CIFSSMBNegotiate ( xid , pSesInfo ) ;
2007-07-13 04:33:32 +04:00
if ( rc = = - EAGAIN )
2005-04-17 02:20:36 +04:00
rc = - EHOSTDOWN ;
}
2007-07-10 05:16:18 +04:00
if ( rc = = 0 ) {
2005-04-17 02:20:36 +04:00
spin_lock ( & GlobalMid_Lock ) ;
2008-08-18 23:41:05 +04:00
if ( server - > tcpStatus ! = CifsExiting )
server - > tcpStatus = CifsGood ;
2005-04-17 02:20:36 +04:00
else
rc = - EHOSTDOWN ;
spin_unlock ( & GlobalMid_Lock ) ;
}
2005-04-29 09:41:05 +04:00
first_time = 1 ;
2005-04-17 02:20:36 +04:00
}
2008-08-06 09:11:33 +04:00
if ( rc )
goto ss_err_exit ;
pSesInfo - > flags = 0 ;
2008-08-18 23:41:05 +04:00
pSesInfo - > capabilities = server - > capabilities ;
2008-08-06 09:11:33 +04:00
if ( linuxExtEnabled = = 0 )
pSesInfo - > capabilities & = ( ~ CAP_UNIX ) ;
2009-04-30 20:13:32 +04:00
2008-08-06 09:11:33 +04:00
cFYI ( 1 , ( " Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d " ,
2008-08-18 23:41:05 +04:00
server - > secMode , server - > capabilities , server - > timeAdj ) ) ;
2009-04-30 20:13:32 +04:00
rc = CIFS_SessSetup ( xid , pSesInfo , first_time , nls_info ) ;
2008-08-06 09:11:33 +04:00
if ( rc ) {
cERROR ( 1 , ( " Send error in SessSetup = %d " , rc ) ) ;
} else {
cFYI ( 1 , ( " CIFS Session Established successfully " ) ) ;
2009-04-30 20:13:32 +04:00
spin_lock ( & GlobalMid_Lock ) ;
pSesInfo - > status = CifsGood ;
pSesInfo - > need_reconnect = false ;
spin_unlock ( & GlobalMid_Lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-06 09:11:33 +04:00
2005-04-17 02:20:36 +04:00
ss_err_exit :
return rc ;
}